From: Dr J R Stockton on
In comp.lang.javascript message <3200480.OGUtdWV9SE(a)PointedEars.de>,
Thu, 3 Jun 2010 09:43:22, Thomas 'PointedEars' Lahn <PointedEars(a)web.de>
posted:

>Dr J R Stockton wrote:
>
>> Thomas 'PointedEars' Lahn posted:
>>> Dr J R Stockton wrote:
>>>> Thomas 'PointedEars' Lahn posted:
>>>>> Dr J R Stockton wrote:
>>>>>> That indeed gives -3.141592653589793; but use instead Math.PI/10 and
>>>>>> it gives 0.3141592653589793. Whenever parseInt(s, 16) gives a zero,
>>>>>> your code will give a positive result.
>>>>> ACK, thanks. ISTM that checking whether the first character of the
>>>>> representation is a `-' solves this particular problem. Again, largely
>>>>> untested:
>>>> Entirely unnecessary. Just use the sign of the number 'i'.
>>> I had: (i < 0 ? -1 : 1). But *you* pointed out to me that `i' would be 0
>>> if the absolute value of the represented number would be less than 1.
>>
>> Indeed you did; and, as you know, your test does not suffice, since it
>> does not always give the sign of the number 'i'.
>>
>> I repeat - you need to use the sign of the number 'i'.
>
>Since the value of `i' is the return value of `parseInt(s, base)' here, in
>the border case that `s' represents a number which absolute value is less
>than 1, `i' has no sign or IOW its sign is always positive. It is therefore
>hard to see how its sign could be useful.
>
>> You so frequently insist that others search the archives; you should do
>> so yourself. The matter was referred to sometime in the years 200x.
>> Careful reading of ECMA 262 3/5 could help you.
>
>Instead of making yet another lame attempt at an ad hominem attack, and
>speaking in riddles, you could just have said how you would do it. Suppose,
>just suppose, that I do exactly what you just did, then you are no better
>than me. This should give you pause.

Telling you to search the archives has evidently, as intended, annoyed
you; you have found it to be not really helpful. Perhaps, therefore,
you will now abandon the practice of making such a recommendation to
others as frequently as you have been doing. But I doubt it.



You are really being perversely obtuse this week. The answer is on my
Web site, in the obvious place. AND it is also in the article which I
posted to this thread just a week ago today. AND it is fairly obvious
from what ECMA 262 says.

Granted, the additional code in my article to handle the case of strings
starting '-0.' is not easy to see, since it is only two characters; but
there's a whole sentence of clue directly preceding the code.


But, really, you should be aware that, apart from the case of NaN(s),
the IEEE Double format CANNOT represent an unsigned quantity. Of
course.
parseInt(+0.5) == parseInt(-0.5) // -> true
but 1/parseInt(+0.5) == 1/parseInt(-0.5) // -> false

My reading of ECMA 262 is that parseInt is required firstly to remove
whitespace and set /sign/ to 1, then if the string starts '-' set /sign/
to -1. It then processes the rest to get a (non-negative) /number/, and
returns /sign/ times /number/. Now read ECMA 11.5.2. Function parseInt
always returns an appropriately-SIGNED Number.

AFAIK, parseInt cannot return an infinity. In the present case, we
expect a finite, and signed, value in 'i' - and the sign can ALWAYS be
determined by comparing a zero (of either sign) with the reciprocal of
'i'.


I chose to use (2*(1/A>0)-1) where you have used (i < 0 ? -1 : 1)
but you could use (1/i < 0 ? -1 : 1). Again, 'i' is a bad choice of
identifier where you do not know in what font it will be read (and I is
not much better).

Only in strings can JavaScript represent an unsigned zero.




IIRC, the case of the nasty format shown by -.12345 can be handled
with a RegExp replace of (\d*)\. by 0$1 .



ASIDE, as .toString(radix) is also about string/number interconversion :
ISTM that looking, for each radix 2 to 36, at the last character
of Math.random().toString(radix), very repeatedly, the set of
characters obtained is not the same in any 2 of the 5 browsers
on this PC - Firefox 3.0.19 alone giving the expected "any non-
zero digit in the base". My js-randm.htm refers.


--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.
Grandson-Of-RFC1036 is released. RFC 5536 Netnews Article Format is a
subset of Internet Message Format which is described in RFC 5532. The
RFCs are read together to determine standard Netnews article format.
From: Dr J R Stockton on
In comp.lang.javascript message <1J7cUsISsBAMFwdk(a)invalid.uk.co.demon.me
rlyn.invalid>, Fri, 28 May 2010 20:35:46, Dr J R Stockton
<reply1021(a)merlyn.demon.co.uk> posted:

>ISTM that parseInt("-0", 16) does indeed return -0.
>
> S = "-45.6"
> A = parseInt(S, 16)
> if (S = S.split(".")[1])
> A += (2*(1/A>0)-1) * parseInt(S, 16) / Math.pow(16, S.length)
> // -> -69.375
>
>That is undertested. A number string should always have a digit before
>its basal separator if any. Have no non-digit terminator.


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 }

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.
Grandson-Of-RFC1036 is released. RFC 5536 Netnews Article Format is a
subset of Internet Message Format which is described in RFC 5532. The
RFCs are read together to determine standard Netnews article format.
From: Scott Sauyet on
Dr J R Stockton wrote:
> 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.

--
Scott
From: Dr J R Stockton on
In comp.lang.javascript message <5583d1fb-9746-4999-9d7b-46a0e831bad5(a)e5
g2000yqn.googlegroups.com>, Wed, 16 Jun 2010 08:30:51, Scott Sauyet
<scott.sauyet(a)gmail.com> posted:

>Dr J R Stockton wrote:
>> 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.

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk DOS 3.3, 6.20; WinXP.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQqish topics, acronyms & links.
PAS EXE TXT ZIP via <URL:http://www.merlyn.demon.co.uk/programs/00index.htm>
My DOS <URL:http://www.merlyn.demon.co.uk/batfiles.htm> - also batprogs.htm.
From: Scott Sauyet on
Dr J R Stockton wrote:
> In comp.lang.javascript message <5583d1fb-9746-4999-9d7b-46a0e831bad5(a)e5
> g2000yqn.googlegroups.com>, Wed, 16 Jun 2010 08:30:51, Scott Sauyet
> <scott.sau...(a)gmail.com> posted:
>>Dr J R Stockton wrote:
>>    http://scott.sauyet.com/Javascript/Test/2010-06-16a/
> 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.

Good idea, it's in the latest version here:

http://scott.sauyet.com/Javascript/Test/2010-06-18a/

as is a try-catch around the call to each function with some minimal
error reporting.


> Testing '0.fgr' to base 36 on your page, all but yours are perfect in
> Firefox 3.0.19.

Ahh, yes, I can see that mine can lose some precision with smaller
inputs, while it gains some at larger length inputs.

> Try '0.fgr' to base 27 !

That doesn't bother me much at least until I figure out how it's
supposed to react to illegitimate input. If you try the same thing to
base 10 you get other surprising results.

> 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.

Right, but that does not mean that we can't get more exact results
when we calculate with additional digits. I think maybe it would be
best to combine these techniques. I have some ideas how, but have not
yet tried to implement them as my brain is too fuzzy at the moment.
(Midnight here.) Briefly, the idea would be to figure out and cache
the maximum number of digits for each base that fit in 53 bits, use
those for the most exact results, but then calculate a few digits
further with the technique I used earlier.


> 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.

Yes, but a IEEE754 number can sometimes still have a bit more
precision than the result of that integer divided by the relevant
power of the radix.

> 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.

I've added this test too.


> 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.

I've included it on the page without considering it thoroughly
enough. I'll try to have another look over the weekend.

A very interesting discussion! Thank you,

--
Scott