In comp.lang.javascript message <5583d1fb-9746-4999-9d7b-46a0e831bad5@e5
g2000yqn.googlegroups.com>, Wed, 16 Jun 2010 08:30:51, Scott Sauyet
Dr said:
This accepts zero or more digits before the point, and trailing non-
digits, and ludicrously long input fractions.
function parsFlotB(S, R) {
S = S.replace(/(\d*\.)/, "0$1") // ensure \d+ before point
var A = parseInt(S, R)
if (S = S.split(".")[1]) { var NR = 1, L = 0
S = S.substring(0, 99) // Crude partial fix for excess length
while (1+parseInt(S.charAt(L++), R)) NR *= R // good digits
A += (1/A>0?+1:-1) * parseInt(S, R) / NR }
return A }
This still loses some possible precision. Try the first example at
http://scott.sauyet.com/Javascript/Test/2010-06-16a/
(Doesn't work in IE, and I just can't bother to figure out why right
now.)
My technique is certainly inefficient, but it does seem to gain a
digit or two of precision over the others presented.
I recommend monospace for input type=text , by CSS.
I suggest that you show the result of the "parseFloat" in addition to
the toString thereof; toString is clearly not reliable cross-browser for
less popular radixes.
Testing '0.fgr' to base 36 on your page, all but yours are perfect in
Firefox 3.0.19.
Try '0.fgr' to base 27 !
Try almost any fraction to a large odd base on Chrome; the "results" are
unreasonably long in all four cases. Method Number.toString, used there
for display, is untrustworthy. That is why the above code includes
S = S.substring(0, 99) .
Your base-36 test uses "0.r3j6f0mqo4fr3j6f0m" which has 18 radical
places, so the string has more resolution than an IEEE Double can give;
that of course is why results are shorter.
Your parseFraction seems to loop over all of the fraction digits,
repeatedly dividing by base. That perhaps means repeated rounding
errors, unless the JavaScript engine is unreasonably clever. Using
parseInt on the fractional part should be better, since parseInt ought
to be exact up to a result of 2^53.
For such functions, it would be useful to have exact statements of how,
with radix=10, they differ from ECMA 15.1.2.3 parseFloat (string). I
guess all disallow ExponentPart. You and Jorge give NaN for a string
such as "11.001 2*2=4". You accept "++55". Jorge, I think, crashes if
not given a radical point. Mine gives 0 from ".", which is too
tolerant.
For meaningful tests of accuracy, ISTM essential to have a "master"
parseFloat or a "master" "toString" which is absolutely accurate, using
absolutely accurate arithmetic throughout.
I have, via sig line 3, a programmable megadigit integer arithmetic
package for bases 2 to 16, which might be useful here - Pascal/Delphi
LONGCALC. If I were starting again, I could use bases 2 to 256 equally
easily (apart from the representation as strings), but I don't fancy
changing it now.
OTOH, how about the following, which is intended to be evidently good
without regard to speed, and expects proper input only :-
function ExactPF(S, Rdx) { var J, L = 0, R = 0, RN = 1
S = S.split(".")
var Int = S[0].split("")
var Frc = S[1].split("")
var Sgn = Int[0] == "-" ? -1 : +1
if (Sgn == -1) Int.shift(1)
for (J = 0 ; J < Int.length ; J++)
L = L * Rdx + parseInt(Int[J], Rdx)
for (J = 0 ; J < Frc.length ; J++) { RN *= Rdx
R = R * Rdx + parseInt(Frc[J], Rdx) }
return Sgn * ( L + R/RN ) } // Consider case of L or R exceeding 2^53
Note that it uses parseInt only on single characters, which reduces the
chance of error. I've nor found any; but it is practical to test
parseInt with all bases and all single-character strings, but not with
all multi-digit strings.