See my comment above. I would suggest a bit different expression:
preg_replace("/(\d+(?:\.\d+)?)(\s*)\@/", "$1$2%", $str);
This expression will match 5@, but 5.5@ as well (with or without floating point). However it will not match 5.@.
\d means numbers, equal to [0-9], the + (plus) means 1 or more, but not 0 occurrences. The second expression starting with with ?: (which means not to match as group) means to find . (dot) immediately after the first number sequence and to be followed by numbers - whole zero or one time (not to match 5.15.25@).
We then check for a spaces (0 or more times), then we turn them back after replacing with $2.
.in[]means almost any character with some modifiers all. Its not\.