Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Math.PI.toString(16) -> 3.243f6a8885a3 and back

68 views
Skip to first unread message

Dr J R Stockton

unread,
May 26, 2010, 4:44:16 PM5/26/10
to
Some may not have noted that Number.toString(16) handles non-integers.
Math.PI.toString(16) -> 3.243f6a8885a3
1e44.toString(16) -> 47bf19673df53000000000000000000000000
Math.random().toString(2) => 0 . /[01]{1,53}/

ECMA 262 (5) 15.7.4.2 Number.prototype.toString ( [ radix ] )
makes no mention of non-integers.

A Hex integer string H can be turned into a Number by
+ ( "0x" + H )
but that does not work for a Hex fraction string. Is there in fact an
easy built-in way of converting non-integer Hex strings to Number?

Otherwise, I suggest that ECMA 6 should specify a Method whereby for ANY
Number X the result of X.toString(B) can be converted to the original X
(disregarding the sign of zero).

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

Ry Nohryb

unread,
May 26, 2010, 7:14:53 PM5/26/10
to
On May 26, 10:44 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:

> Some may not have noted that Number.toString(16) handles non-integers.
>         Math.PI.toString(16) -> 3.243f6a8885a3
>         1e44.toString(16) -> 47bf19673df53000000000000000000000000
>         Math.random().toString(2) => 0 . /[01]{1,53}/

My dear friend Garrett and I know that at least since:
http://groups.google.com/group/comp.lang.javascript/msg/936a683de6159fd0

> ECMA 262 (5) 15.7.4.2 Number.prototype.toString ( [ radix ] )
> makes no mention of non-integers.
>
> A Hex integer string H can be turned into a Number by
>         + ( "0x" + H )
> but that does not work for a Hex fraction string.  Is there in fact an
> easy built-in way of converting non-integer Hex strings to Number?

a= 113356057.78731406
--> 113356057.78731406

b= a.toString(16).split('.');
--> [ "6c1ad19", "c98d6a" ]

c= +( '0x'+ b.join('') ) / Math.pow(16, b[1].length)
--> 113356057.78731406

> Otherwise, I suggest that ECMA 6 should specify a Method whereby for ANY
> Number X the result of X.toString(B) can be converted to the original X
> (disregarding the sign of zero).
--

Jorge.

Evertjan.

unread,
May 27, 2010, 5:11:52 AM5/27/10
to
Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:

> a= 113356057.78731406
> --> 113356057.78731406
>
> b= a.toString(16).split('.');
> --> [ "6c1ad19", "c98d6a" ]
>
> c= +( '0x'+ b.join('') ) / Math.pow(16, b[1].length)
> --> 113356057.78731406

or just add the fractional part to the integer part.

===========================================

Try this for any radix [0 .. 36]:

<script type='text/javascript'>

document.write(radixTo10('6c1ad19.c98d6a',16) + '<br>')
// --> 113356057.78731406
document.write(radixTo10('778',8) + '<br>')
// --> 511
document.write(radixTo10('z',36) + '<br>')
// --> 35
document.write(radixTo10('10',36) + '<br>')
// --> 36


function radixTo10int(v,radix) {
var n = 0;
for (i=0;i<v.length;i++) {
temp = v[i];
temp = (temp>'9')
? 10+temp.charCodeAt(0)-'a'.charCodeAt(0)
: +temp;
//if (temp>radix-1) return 'error';
n *= radix;
n += temp;
};
return n;
};

function radixTo10(v,radix) {
v = v.toLowerCase().split('.');
if (v.length==1)
return radixTo10int(v[0],radix);
return radixTo10int(v[0],radix) +
radixTo10int(v[1],radix) / Math.pow(radix,v[1].length);
};

</script>


--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

Evertjan.

unread,
May 27, 2010, 5:16:25 AM5/27/10
to
Evertjan. wrote on 27 mei 2010 in comp.lang.javascript:

> Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:
>
>> a= 113356057.78731406
>> --> 113356057.78731406
>>
>> b= a.toString(16).split('.');
>> --> [ "6c1ad19", "c98d6a" ]
>>
>> c= +( '0x'+ b.join('') ) / Math.pow(16, b[1].length)
>> --> 113356057.78731406
>
> or just add the fractional part to the integer part.
>
> ===========================================
>
> Try this for any radix [0 .. 36]:
>
> <script type='text/javascript'>
>
> document.write(radixTo10('6c1ad19.c98d6a',16) + '<br>')
> // --> 113356057.78731406
> document.write(radixTo10('778',8) + '<br>')
> // --> 511

sorry:

document.write(radixTo10('777',8) + '<br>')

Ry Nohryb

unread,
May 27, 2010, 7:56:32 AM5/27/10
to
On May 27, 11:11 am, "Evertjan." <exjxw.hannivo...@interxnl.net>
wrote:

Cute. How about this one :-) ?

String.prototype.toFP= function (base, digits, r, w, n) {
digits= "0123456789abcdefghijklmnopqrstuvwxyz", r= 0;
w= (n= this.toLowerCase().split('.'))[0].length;
n.join('').split('').forEach(function (s) {
r+= digits.indexOf(s) * Math.pow(base, --w) });
return r;
};

a= Math.PI
--> 3.141592653589793
b= a.toString(16)
--> "3.243f6a8885a3"
a.toFP(16)
--> 3.141592653589793
b= a.toString(36)
--> "3.53i5ab8p5fc5vayqter60f6r"
b.toFP(36)
--> 3.141592653589793
b= a.toString(2)
--> "11.001001000011111101101010100010001000010110100011"
b.toFP(2)
--> 3.141592653589793
--
Jorge.

Evertjan.

unread,
May 27, 2010, 9:49:49 AM5/27/10
to
Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:

> String.prototype.toFP= function (base, digits, r, w, n) {
> digits= "0123456789abcdefghijklmnopqrstuvwxyz", r= 0;
> w= (n= this.toLowerCase().split('.'))[0].length;
> n.join('').split('').forEach(function (s) {
> r+= digits.indexOf(s) * Math.pow(base, --w) });
> return r;
>};
>

Nice!

since all non-'digit' chars would count as -1,
I would test for that,
as that makes debugging extreemly difficult.

String.prototype.toFP= function (base, digits, r, w, n) {

if (/[^0-9a-z\.]/i.test(this)) return NaN; // <<<---


digits= "0123456789abcdefghijklmnopqrstuvwxyz", r= 0;
w= (n= this.toLowerCase().split('.'))[0].length;
n.join('').split('').forEach(function (s) {
r+= digits.indexOf(s) * Math.pow(base, --w) });
return r;
};

--

Ry Nohryb

unread,
May 27, 2010, 10:25:09 AM5/27/10
to
On May 27, 3:49 pm, "Evertjan." <exjxw.hannivo...@interxnl.net> wrote:
>
> Nice!
>
> since all non-'digit' chars would count as -1,
> I would test for that,
> as that makes debugging extreemly difficult.
>
> String.prototype.toFP= function (base, digits, r, w, n) {
>   if (/[^0-9a-z\.]/i.test(this)) return NaN; // <<<---
>   digits= "0123456789abcdefghijklmnopqrstuvwxyz", r= 0;
>   w= (n= this.toLowerCase().split('.'))[0].length;
>   n.join('').split('').forEach(function (s) {
>     r+= digits.indexOf(s) * Math.pow(base, --w) });
>   return r;
> };

Yes, good idea. And instead of n.join('').split('').forEach(f) an
[].forEach.call(n.join(''), f)... might be faster:

String.prototype.toFP= function (base, digits, w, n, r) {


if (/[^0-9a-z\.]/i.test(this)) return NaN;

digits= "0123456789abcdefghijklmnopqrstuvwxyz";
w= (n= this.toLowerCase().split('.'))[r= 0].length;
n.forEach.call(n.join(''), function (s) {


r+= digits.indexOf(s) * Math.pow(base, --w) });
return r;
};

What do we do with the sign ?
--
Jorge.

Evertjan.

unread,
May 27, 2010, 2:16:34 PM5/27/10
to
Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:


this2 = this;
minus = 1;
if (this2.substr(0,1)=='-') {
this2 = this2.substr(1); // or .slice()?
minus = -1;
};
.........this2.........
return minus*r;

Thomas 'PointedEars' Lahn

unread,
May 27, 2010, 5:07:31 PM5/27/10
to
Dr J R Stockton wrote:

> Some may not have noted that Number.toString(16) handles non-integers.
> Math.PI.toString(16) -> 3.243f6a8885a3
> 1e44.toString(16) -> 47bf19673df53000000000000000000000000
> Math.random().toString(2) => 0 . /[01]{1,53}/
>
> ECMA 262 (5) 15.7.4.2 Number.prototype.toString ( [ radix ] )
> makes no mention of non-integers.

It does not have to mention non-integers as all Number values are internally
represented as IEEE-754 double-precision floating-point values, which by
definition includes non-integers.

| If radix not present or is undefined the Number 10 is used as the value of
| radix. If ToInteger(radix) is the Number 10 then this Number value is
| given as an argument to the ToString abstract operation; the resulting
| String value is returned.
|
| [...]
| If ToInteger(radix) is an integer from 2 to 36, but not 10, the result is
| a String representation of this Number value using the specified radix.
| Letters a-z are used for digits with values 10 through 35. The precise
| algorithm is implementation-dependent if the radix is not 10, however the
| algorithm should be a generalization of that specified in 9.8.1.



> A Hex integer string H can be turned into a Number by
> + ( "0x" + H )

Or simply parseInt(H, 16).

> but that does not work for a Hex fraction string. Is there in fact an
> easy built-in way of converting non-integer Hex strings to Number?

No, I don't think so. Obviously you could do this:

var s = "f.0c";
var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];

/* 15.046875 = 15 + 12 * Math.pow(16, -2) */
var n = parseInt(s, 16) + parseInt(f, 16) / Math.pow(16, f.length);

> Otherwise, I suggest that ECMA 6 should specify a Method whereby for ANY
> Number X the result of X.toString(B) can be converted to the original X
> (disregarding the sign of zero).

It would suffice if parseFloat() could take a second argument to specify the
base, as does parseInt(). But while it would be good to have it specified
in _ECMAScript Ed._ 6 ("Harmony"), I do not think we really need ES6 (and
probably to wait another 10 years) for that. It could, for example, be
implemented in JavaScript 1.9 as can be expected from Firefox 4.0, and then,
through competition, copied by other implementations like so many other
features before.


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16

Ry Nohryb

unread,
May 28, 2010, 7:34:28 AM5/28/10
to
On May 27, 11:07 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...)

>   var s = "f.0c";
>   var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>
>   /* 15.046875 = 15 + 12 * Math.pow(16, -2) */
>   var n = parseInt(s, 16) + parseInt(f, 16) / Math.pow(16, f.length);
> (...)

We're almost there, but not yet:

function pointyParseFloat (s, base) {


var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];

return parseInt(s, base) + parseInt(f, base) / Math.pow(base,
f.length);
}

pointyParseFloat(Math.PI.toString(16), 16)
--> 3.141592653589793

pointyParseFloat(Math.PI.toString(33), 33)
--> 3.121212121212121

pointyParseFloat((-Math.PI).toString(16), 16)
--> -2.858407346410207

String.prototype.toFP= function (base, digits, w, n, r) {
if (/[^0-9a-z\.]/i.test(this)) return NaN;
digits= "0123456789abcdefghijklmnopqrstuvwxyz";

r= parseInt((n= this.toLowerCase().split('.'))[w= 0], base);
n.forEach.call(n[1], function (s) {


r+= digits.indexOf(s) * Math.pow(base, --w) });
return r;
};

(Math.PI).toString(16).toFP(16)
--> 3.141592653589793

(Math.PI).toString(33).toFP(33)
--> 3.141592653589793

(-Math.PI).toString(33).toFP(33)
--> NaN

--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:06:46 AM5/28/10
to
On May 28, 1:34 pm, Ry Nohryb wrote:

> On May 27, 11:07 pm, Thomas 'PointedEars' Lahn wrote:
>
> >   (...)
> >   var s = "f.0c";
> >   var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>
> >   /* 15.046875 = 15 + 12 * Math.pow(16, -2) */
> >   var n = parseInt(s, 16) + parseInt(f, 16) / Math.pow(16, f.length);
> >   (...)
>
> We're almost there, but not yet:
> (...)

How about this one ?

String.prototype.toFP= function (base, d, w, n, r, s) {
if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
d= "0123456789abcdefghijklmnopqrstuvwxyz";
s= (r= parseInt((n= this.split('.'))[w= 0], base)) < 0 ? -1 : 1;
n= n[1].toLowerCase().split('');
while (n.length) r+= s* d.indexOf(n.shift())* Math.pow(base, --w);
return r;
};

(-Math.PI).toString(33).toFP(33)
--> -3.141592653589793

Math.PI.toString(33).toFP(33)
--> 3.141592653589793

Math.PI.toString(16).toFP(16)
--> 3.141592653589793

(-Math.PI).toString(2).toFP(2)
--> -3.141592653589793

"-dead.bee".toFP(16).toString(16)
"-dead.bee"

"+bad.c0ffee".toFP(16).toString(16)
"bad.c0ffee"
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:17:37 AM5/28/10
to
On May 28, 2:06 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
>
> How about this one ?
>
> String.prototype.toFP= function (base, d, w, n, r, s) {
>   if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
>   d= "0123456789abcdefghijklmnopqrstuvwxyz";
>   s= (r= parseInt((n= this.split('.'))[w= 0], base)) < 0 ? -1 : 1;
>   n= n[1].toLowerCase().split('');
>   while (n.length) r+= s* d.indexOf(n.shift())* Math.pow(base, --w);
>   return r;
>
> };

D'oh, not yet... :-)

"Pointy.isUgly".toFP(36).toString(36)
--> "pointy.isugkchaor"
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 8:34:28 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> var s = "f.0c";
>> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>>
>> /* 15.046875 = 15 + 12 * Math.pow(16, -2) */
>> var n = parseInt(s, 16) + parseInt(f, 16) / Math.pow(16, f.length);
>> (...)
>
> We're almost there, but not yet:
>
> function pointyParseFloat (s, base) {
> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
> return parseInt(s, base) + parseInt(f, base) / Math.pow(base,
> f.length);
> }
>

> [...]
> pointyParseFloat((-Math.PI).toString(16), 16)
> --> -2.858407346410207

Yes, good catch; we need to consider the sign with addition, e.g.:

var s = (-Math.PI).toString(16);
var i = parseInt(s, 16);


var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];

var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);



> String.prototype.toFP= function (base, digits, w, n, r) {
> if (/[^0-9a-z\.]/i.test(this)) return NaN;
> digits= "0123456789abcdefghijklmnopqrstuvwxyz";
> r= parseInt((n= this.toLowerCase().split('.'))[w= 0], base);
> n.forEach.call(n[1], function (s) {
> r+= digits.indexOf(s) * Math.pow(base, --w) });
> return r;
> };

I prefer using regular expressions where possible but only where necessary,
and to avoid callbacks. So my current quick hack looks as follows:

/**
* Parses a string of characters into a Number value. It replaces the
* built-in function in that it supports fractional parts on non-decimal
* representations, and uses the built-in for decimal representations.
*
* @param s : String
* String representation to be parsed
* @param iBase : Number
* Numeric base of the representation, from 2 to 36 inclusive.
* @return number
*/
var parseFloat = jsx.string.parseFloat = (function () {
var origPF = parseFloat;

return function (s, iBase) {
if (!iBase || iBase == 10)
{
return origPF(s);
}

var
i = (s.indexOf(".") != 0 ? parseInt(s, iBase) : 0),
chars = (iBase < 10
? "0-" + String.fromCharCode(47 + iBase)
: "\\d"
+ (iBase > 10
? "a"
+ (iBase > 11
? "-" + String.fromCharCode(86 + iBase)
: "")
: "")),
f = (s.match(new RegExp("\\.([" + chars + "]+)", "i")) || [, "0"])[1],

return i + (i < 0 ? -1 : 1)
* parseInt(f, iBase) / Math.pow(iBase, f.length);
};
}());

As for your misusing arguments as local variables and the resulting
unreadable, unmaintainable, and insecure code, that has been discussed ad
nauseam. Will you ever learn?

> (Math.PI).toString(16).toFP(16)
> --> 3.141592653589793
>
> (Math.PI).toString(33).toFP(33)
> --> 3.141592653589793
>
> (-Math.PI).toString(33).toFP(33)
> --> NaN

So you are essentially saying that you managed to produce code garbage,
as usual?

And stop calling me Pointy, Georgina.

Ry Nohryb

unread,
May 28, 2010, 8:46:02 AM5/28/10
to
On May 28, 2:34 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Ry Nohryb wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> var s = "f.0c";
> >> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>
> >> /* 15.046875 = 15 + 12 * Math.pow(16, -2) */
> >> var n = parseInt(s, 16) + parseInt(f, 16) / Math.pow(16, f.length);
> >>   (...)
>
> > We're almost there, but not yet:
>
> > function pointyParseFloat (s, base) {
> >   var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
> >   return parseInt(s, base) + parseInt(f, base) / Math.pow(base,
> > f.length);
> > }
>
> > [...]
> > pointyParseFloat((-Math.PI).toString(16), 16)
> > --> -2.858407346410207
>
> Yes, good catch; we need to consider the sign with addition, e.g.:
>
>   var s = (-Math.PI).toString(16);
>   var i = parseInt(s, 16);
>   var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>   var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);
> (...)

Better, but still not there:

function pointyParseFloat (s, base) {
var i = parseInt(s, base);


var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];

return i + (i < 0 ? -1 : 1) * parseInt(f, base) / Math.pow(base,
f.length);
}

pointyParseFloat((-Math.PI).toString(33), 33)
--> -3.121212121212121
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:50:36 AM5/28/10
to
On May 28, 2:34 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...)

> I prefer using regular expressions where possible but only where necessary,
> and to avoid callbacks.  So my current quick hack looks as follows:
>
> /**
>  * Parses a string of characters into a Number value.  It replaces the
>  * built-in function in that it supports fractional parts on non-decimal
>  * representations, and uses the built-in for decimal representations.
>  *
>  * @param s : String
>  *   String representation to be parsed
>  * @param iBase : Number
>  *   Numeric base of the representation, from 2 to 36 inclusive.
>  * @return number
>  */
> var parseFloat /*= jsx.string.parseFloat*/ = (function () {

>   var origPF = parseFloat;
>
>   return function (s, iBase) {
>     if (!iBase || iBase == 10)
>     {
>       return origPF(s);
>     }
>
>     var
>       i = (s.indexOf(".") != 0 ? parseInt(s, iBase) : 0),
>       chars = (iBase < 10
>         ? "0-" + String.fromCharCode(47 + iBase)
>         : "\\d"
>           + (iBase > 10
>             ? "a"
>               + (iBase > 11
>                 ? "-" + String.fromCharCode(86 + iBase)
>                 : "")
>             : "")),
>       f = (s.match(new RegExp("\\.([" + chars + "]+)", "i")) || [, "0"])[1],
>
>     return i + (i < 0 ? -1 : 1)
>       * parseInt(f, iBase) / Math.pow(iBase, f.length);
>   };
>
> }());


parseFloat(Math.PI.toString(33), 33)
--> NaN

Cool !
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:53:03 AM5/28/10
to
On May 28, 2:34 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...)

> As for your misusing arguments as local variables and the resulting
> unreadable

You may find it so, not me.

> unmaintainable

you opinion

> and insecure code

each and every parameter is properly initialized before use.

> , that has been discussed ad
> nauseam.  Will you ever learn?

yes, and faster than you, it seems to me.

> (...)
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:57:18 AM5/28/10
to
On May 28, 2:34 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...)

> So you are essentially saying that you managed to produce code garbage,
> as usual?

LOL^2

> And stop calling me Pointy, Georgina.

LOL, Georgina ? No, leave that or I'll call you MissPointy.
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 8:57:46 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:


>> Ry Nohryb wrote:
>> > [...]
>> > pointyParseFloat((-Math.PI).toString(16), 16)
>> > --> -2.858407346410207
>>
>> Yes, good catch; we need to consider the sign with addition, e.g.:
>>
>> var s = (-Math.PI).toString(16);
>> var i = parseInt(s, 16);
>> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>> var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);
>> (...)
>
> Better, but still not there:
>
> function pointyParseFloat (s, base) {
> var i = parseInt(s, base);
> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];

^^^^^


> return i + (i < 0 ? -1 : 1) * parseInt(f, base) / Math.pow(base,
> f.length);
> }
>
> pointyParseFloat((-Math.PI).toString(33), 33)

^^ ^^
> --> -3.121212121212121

You have not considered that this example was suited to *hexadecimal*
representations. parseFloat((-Math.PI).toString(33), 33) and
jsx.string.parseFloat((-Math.PI).toString(33), 33) as posted return
-3.141592653589793 (approx. -Math.PI), as expected.


PointedEars
--
Prototype.js was written by people who don't know javascript for people
who don't know javascript. People who don't know javascript are not
the best source of advice on designing systems that use javascript.
-- Richard Cornford, cljs, <f806at$ail$1$8300...@news.demon.co.uk>

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 8:59:23 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> var parseFloat /*= jsx.string.parseFloat*/ = (function () {
>> var origPF = parseFloat;
>>
>> return function (s, iBase) {
>> if (!iBase || iBase == 10)
>> {
>> return origPF(s);
>> }
>>
>> var
>> i = (s.indexOf(".") != 0 ? parseInt(s, iBase) : 0),
>> chars = (iBase < 10
>> ? "0-" + String.fromCharCode(47 + iBase)
>> : "\\d"
>> + (iBase > 10
>> ? "a"
>> + (iBase > 11
>> ? "-" + String.fromCharCode(86 + iBase)
>> : "")
>> : "")),
>> f = (s.match(new RegExp("\\.([" + chars + "]+)", "i")) || [, "0"])[1],
>>
>> return i + (i < 0 ? -1 : 1)
>> * parseInt(f, iBase) / Math.pow(iBase, f.length);
>> };
>>
>> }());
>
>
> parseFloat(Math.PI.toString(33), 33)
> --> NaN

I cannot confirm this. Where have you tested it?

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 9:02:49 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> As for your misusing arguments as local variables and the resulting
>> unreadable
>
> You may find it so, not me.
>
>> unmaintainable
>
> you opinion

Your code style is being frowned upon by several knowledgable people here.

>> and insecure code
>
> each and every parameter is properly initialized before use.

Unless you happen to forget doing that, which is likely with that code
style.


PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

Ry Nohryb

unread,
May 28, 2010, 9:22:40 AM5/28/10
to
On May 28, 2:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Ry Nohryb wrote:
>
> > parseFloat(Math.PI.toString(33), 33)
> > --> NaN
>
> I cannot confirm this.  Where have you tested it?

Safari / Mac:
navigator.userAgent
--> "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us)
AppleWebKit/534.1+ (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7"
--
Jorge.

Johannes Baagoe

unread,
May 28, 2010, 9:25:36 AM5/28/10
to
Thomas 'PointedEars' Lahn :

> Your code style is being frowned upon by several knowledgable people
> here.

That *could* end up being a circular definition, like Flew's "No true
Scotsman" argument, http://en.wikipedia.org/wiki/No_true_Scotsman
(If someone does not frown upon Jorge's code style, it shows that
that person is not *knowledgeable*.)

Personally, I consider his suggestions interesting and enlightening.
I wouldn't use them in production code destined to be maintained by
cheap labour, but then, this newsgroup is hardly entirely about writing
Web applications in an industrial environment, is it now ? (If it is,
where can I find discussions about the computer language javascript ?)

--
Johannes

Ry Nohryb

unread,
May 28, 2010, 9:26:28 AM5/28/10
to
On May 28, 3:02 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
>

> Your code style is being frowned upon by several knowledgable people here.

♪ We're all ♫ free ♩ to frown ♫

Or not ?

E.g., I have just frowned upon your 23 LOC parsefloat() that doesn't
work.
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 9:53:00 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Ry Nohryb wrote:
>> > parseFloat(Math.PI.toString(33), 33)
>> > --> NaN
>>
>> I cannot confirm this. Where have you tested it?
>
> Safari / Mac:
> navigator.userAgent
> --> "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us)
> AppleWebKit/534.1+ (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7"

Thanks, I am seeing this in Google Chrome 5.0.375.55 beta for Linux (V8
2.1), too.

The reason of this is apparently that the fractional part of
"3.4m6dn4ow9qwe210nr3u0cdqkcnrbmwlh7kmfeapn9fijt38kie44jvdqh2vfrd6ogbvu
rnjq2bqkbr01f97av5k7uaffclrl3hmt2glugpaqe422qgfn81ca8pa73pmt51ewqo9234c
km2twg1qgwmahsv1pdti9bug3bjc9w0sn9ul421p5aanjnfuab9rq3bm5lchsu5aq6000no
i5wcf9c5p5idkgclha9j05bcupqqcb9h08dc3i2v2qcqjks96pgpkmangnavpt7tk6kvrfo
s0qq63iqrgv5nu2i8goh8tjmifwbwf9t3bvcd4r61tbqa05ca16ql0icacmucfcl1h3ceb1
hrdmhhmsp8ri842wn3nj97v7r5i9mdv135qo5jd9bn9chun8n1h11qlgt35mqksnn8ef4p6
kdade1d2t1bfigevwtjnjufm5sc9vhgq7qusio03g1ctrgmukjj5frghkmw1f1dhl4hvr7c
8slmplk66fb34twd9dwkvb16dfi8lbq8nvftmvwo2o4aukf0d252v3go1gtbgfbj8qoqtsf
8hpkkdfw9w686je30nmk6ojecalbc9ifs533e4gucpivw3327b1rc8a7qvqplce4o5agc9s
9h64lia1bker9hhbj7tq6saw68e7c6nqo37v97nbgl8bcgniv3g7ebvrwufnuqsqhlk6fee
7nsj348jwe0nstlnrjcet17sdksk7fo81rwtn6tknpo7lmcmskd4t5lebji6h6riabtauul
s2d49kgak0cu02fbwfklvn6jdlchkn7uwfa7qvncrfrw2umrhpja4hkwgrm261o8cf67c0a
lckiq428lpcvnjub55qkp15l90pbd47w9tupnf87iwjt8stpccka0scrqi7o6v8vmn1b73c
9f4r4g3m11ofcdw5rq7rv89s69mnoumfpark413hsogn5lb4qawo789t7oet5kfolb9ltn9
wm4iqlhi1glc5e2nd9q6jc6dghqcr5epkf2fde1rpd3ii2ouj7bq0pn16n4l28b85thc8ob
3bi7debdwogfnhfaif0v6h4k2i9k39fkrvmlc", which is the 33-ary representation
of Math.PI there, is parsed (because of its length) into `Infinity', while
in JavaScript 1.8.2 the representation is rounded to "3.4m6dn4ow9r" and
therefore the fractional part is not parsed into `Infinity'.

Therefore, it appears to be prudent to truncate the fractional part so that
it is not parsed into `Infinity'. A simple solution is to restrict the
number of characters matched by the regular expression, like:

... new RegExp("\\.([" + chars + "]{1,10})", "i") ...

A more sophisticated solution would be an adaptive algorithm that uses only
as many characters as possible so that the result would not be `Infinity'
given the numeric base. An implementation of that might be available
through the Mozilla sources.


BTW, in case you have not noticed yet, like Safari, Chrome has a Developer
menu (in the first main menu, below the Encoding menu item), which provides
access to the Developer tools, including a script console and a debugger
(which helped me to track this down). That makes using Firebug Lite in
Chrome unnecessary.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 9:59:51 AM5/28/10
to
Johannes Baagoe wrote:

> Thomas 'PointedEars' Lahn :
>> Your code style is being frowned upon by several knowledgable people
>> here.
>
> That *could* end up being a circular definition, like Flew's "No true
> Scotsman" argument, http://en.wikipedia.org/wiki/No_true_Scotsman
> (If someone does not frown upon Jorge's code style, it shows that
> that person is not *knowledgeable*.)

Yes, it could, if one would make that fallacy. However, the outcome of
reviews of Jorge's code style is not the (sole) defining property here.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)

Ry Nohryb

unread,
May 28, 2010, 10:21:27 AM5/28/10
to
On May 28, 3:53 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

No. A "more sophisticated solution" is to fix your broken algorithm:
you're parsing an amount which is less than 1 as an (probably)
enormous integer and then dividing it by another (probably) enormous
integer. That's the problem, not Chrome, your algorithm is the
culprit.

You're, as usual, heavily disoriented.

> BTW, in case you have not noticed yet, like Safari, Chrome has a Developer
> menu (in the first main menu, below the Encoding menu item), which provides
> access to the Developer tools, including a script console and a debugger
> (which helped me to track this down).  That makes using Firebug Lite in
> Chrome unnecessary.

You're telling me ?

See: http://groups.google.com/group/comp.lang.javascript/msg/8e76deb9e1bc4441
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 10:22:34 AM5/28/10
to
On May 28, 3:25 pm, Johannes Baagoe <baa...@baagoe.com> wrote:
>
> Personally, I consider his suggestions interesting and enlightening.
> I wouldn't use them in production code destined to be maintained by
> cheap labour, but then, this newsgroup is hardly entirely about writing
> Web applications in an industrial environment, is it now ? (If it is,
> where can I find discussions about the computer language javascript ?)

Thanks, :-)
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 10:41:31 AM5/28/10
to
On May 28, 3:25 pm, Johannes Baagoe <baa...@baagoe.com> wrote:
> (...)

> where can I find discussions about the computer language javascript ?

Yeah, comp.lang.javascript definitely sounds alike, very much
suspiciously alike.
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 10:59:10 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Ry Nohryb wrote:
>> > Thomas 'PointedEars' Lahn wrote:
>> >> Ry Nohryb wrote:
>> >> > parseFloat(Math.PI.toString(33), 33)
>> >> > --> NaN
>> >>
>> >> I cannot confirm this. Where have you tested it?
>>
>> > Safari / Mac:
>> > navigator.userAgent
>> > --> "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us)
>> > AppleWebKit/534.1+ (KHTML, like Gecko) Version/4.0.5 Safari/531.22.7"
>>
>> Thanks, I am seeing this in Google Chrome 5.0.375.55 beta for Linux (V8
>> 2.1), too.
>>
>> The reason of this is apparently that the fractional part of

>> "3.4m6dn4ow9qwe210nr3u0cdqkcnrbmwlh7kmfeapn9fijt38kie44jvdqh2vfrd[...]",
>> which is the 33-aryrepresentation of Math.PI there, is parsed (because of


>> its length) into `Infinity', while in JavaScript 1.8.2 the representation
>> is rounded to "3.4m6dn4ow9r" and therefore the fractional part is not
>> parsed into `Infinity'.
>>
>> Therefore, it appears to be prudent to truncate the fractional part so
>> that it is not parsed into `Infinity'. A simple solution is to restrict
>> the number of characters matched by the regular expression, like:
>>
>> ... new RegExp("\\.([" + chars + "]{1,10})", "i") ...
>>
>> A more sophisticated solution would be an adaptive algorithm that uses
>> only as many characters as possible so that the result would not be
>> `Infinity' given the numeric base. An implementation of that might be
>> available through the Mozilla sources.
>
> No. A "more sophisticated solution" is to fix your broken algorithm:
> you're parsing an amount which is less than 1 as an (probably)
> enormous integer

Less than 1? You don't know what you are talking about.

> and then dividing it by another (probably) enormous integer. That's the
> problem, not Chrome, your algorithm is the culprit.

As usual you fail to recognize the relevant cause-and-effect relationship.
The problem here is produced by the different implementations of
Number.prototype.toString(), although JavaScriptCore's/V8's behavior cannot
be considered a bug in the ECMAScript implementation, as I have already
indicated in my response to John Stockton.

By comparison you are splitting before you need to (parseInt() can take care
of the point), you are calling the callback futilely at least 886 times in
V8 because precision does not suffice to represent the factor, you fail to
handle the sign properly, and you lose precision every time you call the
callback and increment `r'.



> You're, as usual, heavily disoriented.

Yeah, maybe that is why your code also fails to solve this problem:

,-<news:52ceaeda-f3e2-4aaa...@j9g2000vbp.googlegroups.com>
|
| (-Math.PI).toString(33).toFP(33)
| --> NaN



>> BTW, in case you have not noticed yet, like Safari, Chrome has a
>> Developer menu (in the first main menu, below the Encoding menu item),
>> which provides access to the Developer tools, including a script console
>> and a debugger (which helped me to track this down). That makes using
>> Firebug Lite in Chrome unnecessary.
>
> You're telling me ?

Don't be so vain.

Ry Nohryb

unread,
May 28, 2010, 11:16:54 AM5/28/10
to
On May 28, 4:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Ry Nohryb wrote:
>
> > No. A "more sophisticated solution" is to fix your broken algorithm:
> > you're parsing an amount which is less than 1 as an (probably)
> > enormous integer
>
> Less than 1?  You don't know what you are talking about.

Yes, less than one : [0..1)
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 11:21:58 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Ry Nohryb wrote:
>> > No. A "more sophisticated solution" is to fix your broken algorithm:
>> > you're parsing an amount which is less than 1 as an (probably)
>> > enormous integer
>>
>> Less than 1? You don't know what you are talking about.
>
> Yes, less than one : [0..1)

AISB.

Ry Nohryb

unread,
May 28, 2010, 11:22:53 AM5/28/10
to
On May 28, 4:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Ry Nohryb wrote:
>
> > You're, as usual, heavily disoriented.
>
> Yeah, maybe that is why your code also fails to solve this problem:
>
> ,-<news:52ceaeda-f3e2-4aaa...@j9g2000vbp.googlegroups.com>
> |
> | (-Math.PI).toString(33).toFP(33)
> | --> NaN

You're not paying attention:
http://groups.google.com/group/comp.lang.javascript/msg/f0761684a6595c2a

> String.prototype.toFP= function (base, d, w, n, r, s) {
>   if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
>   d= "0123456789abcdefghijklmnopqrstuvwxyz";
>   s= (r= parseInt((n= this.split('.'))[w= 0], base)) < 0 ? -1 : 1;
>   n= n[1].toLowerCase().split('');
>   while (n.length) r+= s* d.indexOf(n.shift())* Math.pow(base, --w);
>   return r;
>
> };
>

> (-Math.PI).toString(33).toFP(33)
> --> -3.141592653589793
--
Jorge.

Lasse Reichstein Nielsen

unread,
May 28, 2010, 11:29:27 AM5/28/10
to
Ry Nohryb <jo...@jorgechamorro.com> writes:

> String.prototype.toFP= function (base, digits, w, n, r) {

One argument against using unused parameters as local variable
declarations, that hasn't been mentioned yet, is that it might slow
down calling the function.

Simple test:

(function() {
function foo1(a,b,c,d,e) {
e=a;d=e;c=d;b=c;return b;
}
function foo2(a) {
var b,c,d,e;
e=a;d=e;c=d;b=c;return b;
}
var x = 42;
foo1(x);foo2(x); // Make sure they are compiled.
var t0 = Date.now();
for (var i = 0; i < 10000000; i++) {
x = foo1(x);
}
var t1 = Date.now();
for (var i = 0; i < 10000000; i++) {
x = foo2(x);
}
var t2 = Date.now();
alert([t1-t0,t2-t1]);
})()

Safari: 300, 179
Opera 10.54: 132, 116 (maybe not significant).
Chrome dev: 145, 90
Firefox and IE: no noticable difference.
(I also ran the tests with the two loops swapped, to see if going
first made a difference. It did a little in Firefox).

It also prevents the compiler from knowing the initial values
of the variables (but that should be irrelevant if they are
initialized before use on all paths anyway).

/L
--
Lasse Reichstein Holst Nielsen
'Javascript frameworks is a disruptive technology'

Ry Nohryb

unread,
May 28, 2010, 11:37:57 AM5/28/10
to
On May 28, 4:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>

wrote:
> Ry Nohryb wrote:
> > Thomas 'PointedEars' Lahn wrote:
> (...)

> >> BTW, in case you have not noticed yet, like Safari, Chrome has a
> >> Developer menu (in the first main menu, below the Encoding menu item),
> >> which provides access to the Developer tools, including a script console
> >> and a debugger (which helped me to track this down).  That makes using
> >> Firebug Lite in Chrome unnecessary.
>
> > You're telling me ?
>
> Don't be so vain.

I'm not, but I was well aware of that, since a long time ago (years).

And you, Mr. knows-it-all, the master flagellator of newbies, were not
aware -until today- of that debugger (it's both in Safari and in
Chrome: exactly the same: and you open it in both using exactly the
same keystrokes: cmd+option+i) almost TWO years after its
introduction ?

How would you have called that, in your usual (and particular)
tongue ? Completely clueless ? Total cluelessness ?

Let me LOL, please. Let me ROTFLOL.
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 28, 2010, 11:52:47 AM5/28/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Ry Nohryb wrote:
>> > You're, as usual, heavily disoriented.
>>
>> Yeah, maybe that is why your code also fails to solve this problem:
>>
>> ,-<news:52ceaeda-f3e2-4aaa...@j9g2000vbp.googlegroups.com>
>> |
>> | (-Math.PI).toString(33).toFP(33)
>> | --> NaN
>
> You're not paying attention:
> http://groups.google.com/group/comp.lang.javascript/msg/f0761684a6595c2a

It is comparably hard to follow your amok-posting.

Further, we should define the Jorg tropy of code as a measure of its
unreadability; once code as achieved a Jorgtropy greater than 0, that
can only increase with further edits.

Dr J R Stockton

unread,
May 28, 2010, 3:35:46 PM5/28/10
to
In comp.lang.javascript message <Xns9D85CE44...@194.109.133.242>
, Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.ha...@interxnl.net>
posted:

>Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:

You have both missed the point. I wrote :

> Is there in fact an
>easy built-in way of converting non-integer Hex strings to Number?

to which the proper answers must be along the lines of "I cannot see
one" or "ECMA 262 #.##.# indicates that <brief> does it".

I can readily enough code that myself in various ways, the most obvious
being to use parseint(S, 16) for the integer part, split off the
fractional part, use parseInt(S, 16) on that, divide by Math.pow(16,
length) then add or subtract.

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.

But that is, although easy, not built-in. Built-on means something like
using unary + rather than valueOf or getTime on a Date Object would be
if those two methods did not exist - an inconspicuous but useful fearure
of the language as specified, generally missing from non-normative
descriptions of the language.

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05 IE 7.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Command-prompt MiniTrue is useful for viewing/searching/altering files. Free,
DOS/Win/UNIX now 2.0.6; see <URL:http://www.merlyn.demon.co.uk/pc-links.htm>.

Ry Nohryb

unread,
May 28, 2010, 8:04:52 PM5/28/10
to
On May 28, 5:29 pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com>
wrote:

That's very interesting. Any clues as to why ? In any case, first of
all, thanks for sharing. Although imo such a small difference only
makes a difference in the rare cases when you're calling (ultra-short
and fassst) functions at a rate of tens of millions per second, which
is hardly a usual thing. After all, we're talking about differences of
+/-5ns per call, here: 5e-9 seconds, you've got to do quite a lot of
calls in order to notice that, or not ?

> It also prevents the compiler from knowing the initial values
> of the variables (but that should be irrelevant if they are
> initialized before use on all paths anyway).

Ack.
--
Jorge.

Ry Nohryb

unread,
May 28, 2010, 8:06:49 PM5/28/10
to
On May 28, 9:35 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:
> In comp.lang.javascript message <Xns9D85CE4464FCFeej...@194.109.133.242>
> , Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.hannivo...@interxnl.net>

> posted:
>
> >Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:
>
> You have both missed the point.  I wrote :
>
> >  Is there in fact an
> >easy built-in way of converting non-integer Hex strings to Number?
>
> to which the proper answers must be along the lines of "I cannot see
> one" or "ECMA 262 #.##.# indicates that <brief> does it".

Ok. There seems to be an easy way but it's not built-in.

> I can readily enough code that myself in various ways, the most obvious
> being to use parseint(S, 16) for the integer part, split off the
> fractional part, use parseInt(S, 16) on that, divide by Math.pow(16,
> length) then add or subtract.
>
> 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.

function stocktonParseFloat (S, base) {
var A = parseInt(S, base);


if (S = S.split(".")[1])

A += (2*(1/A>0)-1) * parseInt(S, base) / Math.pow(base, S.length);
return A;
}

for (base= 2; base < 37; base++) console.log([base,
stocktonParseFloat(Math.PI.toString(base), base)]);
[2, 3.141592653589793]
[3, 3.141592653589793]
[4, 3.141592653589793]
[5, NaN]
[6, 3.141592653589793]
[7, 3.141592653589793]
[8, 3.141592653589793]
[9, 3.141592653589793]
[10, 3.141592653589793]
[11, NaN]
[12, 3.141592653589793]
[13, 3.141592653589793]
[14, 3.141592653589793]
[15, NaN]
[16, 3.141592653589793]
[17, NaN]
[18, 3.141592653589793]
[19, 3.141592653589793]
[20, 3.141592653589793]
[21, NaN]
[22, 3.141592653589793]
[23, 3.141592653589793]
[24, 3.141592653589793]
[25, NaN]
[26, 3.141592653589793]
[27, NaN]
[28, 3.141592653589793]
[29, NaN]
[30, 3.141592653589793]
[31, 3.141592653589793]
[32, 3.141592653589793]
[33, NaN]
[34, 3.141592653589793]
[35, NaN]
[36, 3.141592653589793]

That algorithm has problems, as you can see.

> But that is, although easy, not built-in.  Built-on means something like
> using unary + rather than valueOf or getTime on a Date Object would be
> if those two methods did not exist - an inconspicuous but useful fearure
> of the language as specified, generally missing from non-normative
> descriptions of the language.

Ok.
--
Jorge.

Lasse Reichstein Nielsen

unread,
May 29, 2010, 5:26:08 AM5/29/10
to
Ry Nohryb <jo...@jorgechamorro.com> writes:

> On May 28, 5:29�pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com>
> wrote:
>> One argument against using unused parameters as local variable
>> declarations, that hasn't been mentioned yet, is that it might slow
>> down calling the function.

...


> That's very interesting. Any clues as to why ?

Best guess is that the extra or missing arguments makes it harder
to just pass the arguments on the stack to the function. You need
to either introduce extra undefined values or change where the
function looks for its arguments.

Also, implementations are likely to optimize for the "common case",
which they assume is to call a function with the number of arguments
that it expects. Anything else triggers special code with extra
overhead.

And possibly, local variables can be optimized better, since it's
certain that noone outside the function can see them. Most
implementations still support the (incrdibly stupid) func.arguments
feature where you can access the arguments of the current call to a
function on the function object itself. That alone breaks some
possible optimizations.

VK

unread,
May 29, 2010, 5:48:54 AM5/29/10
to
On May 29, 1:26 pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com>
wrote:

> And possibly, local variables can be optimized better, since it's
> certain that noone outside the function can see them. Most
> implementations still support the (incrdibly stupid) func.arguments
> feature where you can access the arguments of the current call to a
> function on the function object itself. That alone breaks some
> possible optimizations.

I do not agree that the possibility to send any amount of arguments to
a function without being bothered with formal argument IDs is a stupid
feature. IMHO it is very handy. Also you seem reversing the production
mechanics: arguments object is created and filled on function call in
either case, with formal argument names provided or not. *Then* formal
argument names are used to init them with arguments members from
arguments[0] to arguments.length-1
Respectively I would expect arguments usage to be (fractionally)
quicker than formal argument names usage.


Lasse Reichstein Nielsen

unread,
May 29, 2010, 7:07:08 AM5/29/10
to
VK <school...@yahoo.com> writes:

> On May 29, 1:26�pm, Lasse Reichstein Nielsen <lrn.unr...@gmail.com>
> wrote:
>> And possibly, local variables can be optimized better, since it's
>> certain that noone outside the function can see them. Most
>> implementations still support the (incrdibly stupid) func.arguments
>> feature where you can access the arguments of the current call to a
>> function on the function object itself. That alone breaks some
>> possible optimizations.
>
> I do not agree that the possibility to send any amount of arguments to
> a function without being bothered with formal argument IDs is a stupid
> feature.

And that's not what I said.

I dislike the implicit "arguments" object way of exposing extra arguments,
but I admit that it serves a purpose. There are different approaches and
some would probably have been better for performance and ease of use.

What I don't see any reasonable use for, and a lot of problems with, is
reading the arguments object off the function object:

function foo() {
bar();
}
function bar() {
alert(foo.arguments[0]);
}
foo("Can't keep me secret");

If it wasn't for that feature, calling a function that doesn't use the
arguments object with more arguments than it actually needs, could just
be done by dropping the extra arguments. Instead, the extra arguments
need to be stored, and the function call needs to adapt them to match
the code of the function, which is optimized for the common case of
getting the parameters that it expects.

> IMHO it is very handy. Also you seem reversing the production
> mechanics: arguments object is created and filled on function call in
> either case, with formal argument names provided or not. *Then* formal
> argument names are used to init them with arguments members from
> arguments[0] to arguments.length-1

The arguments object doesn't need to be created unless it is actually
used. An optimizing compiler can keep the arguments on the stack and
work on them directly from there, without creating any arguments object.
That is, unless someone actually uses the arguments object. In that
case, you need to alias the arguments and the arguments object, and
all accesses go through an extra layer of indirection (or more).

The design is most likely derived from an early implementation that
did just this, but that's why more efficient implementations have such
a hard time with this language: The specification derives from a
specific implementation strategy, with unnecessary features that
just happened to be easily implemented using that strategy. [1]

> Respectively I would expect arguments usage to be (fractionally)
> quicker than formal argument names usage.

That's because actual implementations are doing the opposite of what
you expect.

/L
[1] Don't get me started on properties on the RegExp object.

Ry Nohryb

unread,
May 29, 2010, 7:50:03 AM5/29/10
to
On May 28, 4:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...) you are calling the callback futilely at least 886 times in
> V8 because precision does not suffice to represent the factor (...)

[*] FIXED:

String.prototype.toFP= function (base, d, w, n, r, s, pw) {


if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
d= "0123456789abcdefghijklmnopqrstuvwxyz";
s= (r= parseInt((n= this.split('.'))[w= 0], base)) < 0 ? -1 : 1;
n= n[1].toLowerCase().split('');

while(n.length && (pw=Math.pow(base,--w))) r
+=s*d.indexOf(n.shift())*pw;
return r;
};

for (var base=2; base <37; base++) console.log([base,
Math.PI.toString(base).toFP(base)])
-->
[2, 3.141592653589793]
[3, 3.141592653589794]
[4, 3.141592653589793]
[5, 3.1415926535897936]
[6, 3.141592653589793]
[7, 3.141592653589794]
[8, 3.141592653589793]
[9, 3.141592653589794]
[10, 3.141592653589793]
[11, 3.141592653589793]


[12, 3.141592653589793]
[13, 3.141592653589793]
[14, 3.141592653589793]

[15, 3.1415926535897936]
[16, 3.141592653589793]
[17, 3.141592653589793]
[18, 3.141592653589794]
[19, 3.1415926535897922]
[20, 3.141592653589793]
[21, 3.1415926535897936]
[22, 3.1415926535897927]
[23, 3.141592653589793]
[24, 3.141592653589793]
[25, 3.1415926535897936]
[26, 3.141592653589793]
[27, 3.1415926535897927]
[28, 3.141592653589794]
[29, 3.141592653589793]


[30, 3.141592653589793]
[31, 3.141592653589793]
[32, 3.141592653589793]

[33, 3.141592653589793]
[34, 3.141592653589793]
[35, 3.141592653589793]
[36, 3.141592653589793]
--
Jorge.

Evertjan.

unread,
May 29, 2010, 12:02:20 PM5/29/10
to
Dr J R Stockton wrote on 28 mei 2010 in comp.lang.javascript:

> In comp.lang.javascript message <Xns9D85CE44...@194.109.133.242>
> , Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.ha...@interxnl.net>
> posted:
>
>>Ry Nohryb wrote on 27 mei 2010 in comp.lang.javascript:
>
> You have both missed the point. I wrote :
>
>> Is there in fact an
>>easy built-in way of converting non-integer Hex strings to Number?

Perhaps, John, we missed YOUR point.

However we were [or at least I was] just contemplating a general function
for conversion of any root[1..36] floating point string to number value.

Such functions are much safer explicit than embedded,
if speed is not the essense,
as any bug can more easily be delt with,
as you, as king of the embedded bug detectives,
should know.

;-)

btw: in root 1 only the zero value can be expressed.


--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)

Ry Nohryb

unread,
May 29, 2010, 1:10:39 PM5/29/10
to
On May 29, 1:50 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
>
> String.prototype.toFP= function (base, d, w, n, r, s, pw) {
>   if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
>   d= "0123456789abcdefghijklmnopqrstuvwxyz";
>   s= (r= parseInt((n= this.split('.'))[w= 0], base)) < 0 ? -1 : 1;
>   n= n[1].toLowerCase().split('');
>   while(n.length && (pw=Math.pow(base,--w))) r
> +=s*d.indexOf(n.shift())*pw;
>   return r;
>
> };
>
> (...)

Take 3: this one uses the same algorithm of my first post, but, if the
divisor (Math.pow(base, fractionalPartStr.length) is too big
(Infinity) it trims fractionalPartStr down until isFinite(divisor):

/* Tested in Safari, Chrome, Opera & FF */

String.prototype.toFP= function (base, n, r, w, div) {


if (/[^0-9a-z\.+-]/i.test(this)) return NaN;

n= this.split('.');
if (isFinite(r= parseInt(n[0], base))) {
if (w= (n= n[1]).length) {
/*trim until it's finite*/
while (!isFinite(div= Math.pow(base, w))) w--;
r+= (r<0 ? -1:1)* parseInt(n.substr(0, w), base)/ div;
}
}
return r;
};

for (var base=2; base <37; base++) console.log([base,
Math.PI.toString(base).toFP(base)])
-->
[2, 3.141592653589793]

[3, 3.141592653589793]
[4, 3.141592653589793]
[5, 3.141592653589793]


[6, 3.141592653589793]
[7, 3.141592653589793]
[8, 3.141592653589793]
[9, 3.141592653589793]

[10, 3.141592653589793]
[11, 3.141592653589793]
[12, 3.141592653589793]
[13, 3.141592653589793]
[14, 3.141592653589793]

[15, 3.141592653589793]
[16, 3.141592653589793]
[17, 3.141592653589793]


[18, 3.141592653589793]
[19, 3.141592653589793]
[20, 3.141592653589793]

[21, 3.141592653589793]
[22, 3.141592653589793]
[23, 3.141592653589793]
[24, 3.141592653589793]
[25, 3.141592653589793]
[26, 3.141592653589793]
[27, 3.141592653589793]
[28, 3.141592653589793]


[29, 3.141592653589793]
[30, 3.141592653589793]
[31, 3.141592653589793]
[32, 3.141592653589793]
[33, 3.141592653589793]
[34, 3.141592653589793]
[35, 3.141592653589793]
[36, 3.141592653589793]

(-Math.PI).toString(33).toFP(33)
--> -3.141592653589793
--
Jorge.

Dr J R Stockton

unread,
May 29, 2010, 4:13:04 PM5/29/10
to
In comp.lang.javascript message <4430313.M...@PointedEars.de>,
Fri, 28 May 2010 14:34:28, Thomas 'PointedEars' Lahn
<Point...@web.de> posted:

>Yes, good catch; we need to consider the sign with addition, e.g.:
>
> var s = (-Math.PI).toString(16);
> var i = parseInt(s, 16);
> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
> var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);

You need to consider it more effectively, and to test adequately.

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.

Search the archives covering the 200x decade, and you will see that the
relevant facts are known.

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

Thomas 'PointedEars' Lahn

unread,
May 30, 2010, 7:30:58 AM5/30/10
to
Dr J R Stockton wrote:

> Thomas 'PointedEars' Lahn posted:


>> Yes, good catch; we need to consider the sign with addition, e.g.:
>>
>> var s = (-Math.PI).toString(16);
>> var i = parseInt(s, 16);
>> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>> var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);
>
> You need to consider it more effectively, and to test adequately.

Do you know what "quick hack" means?



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

var s = (-Math.PI/10).toString(16);


var i = parseInt(s, 16);

var f = (s.match(/\.([\da-f]{1,198})/i) || [, "0"])[1];
var n = i + (s.charAt(0) == "-" ? -1 : 1) * parseInt(f, 16) / Math.pow(16,
f.length);

But if `s' would be user-defined, it could have leading whitespace, so:

var n = i + (/^\s*-/.test(s) ? -1 : 1) * parseInt(f, 16) / Math.pow(16,
f.length);


Ry Nohryb

unread,
May 30, 2010, 10:28:59 AM5/30/10
to
On May 30, 1:30 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> (...)
>

>   var s = (-Math.PI/10).toString(16);
>   var i = parseInt(s, 16);
>   var f = (s.match(/\.([\da-f]{1,198})/i) || [, "0"])[1];
___________________________________^^^____________________

There's no need to trim f to 198 chars: Math.pow(16, n) overflows at n
=== 256, not @ 199.
--
Jorge.

Thomas 'PointedEars' Lahn

unread,
May 30, 2010, 2:57:44 PM5/30/10
to
Ry Nohryb wrote:

> Thomas 'PointedEars' Lahn wrote:
>> (...)
>>
>> var s = (-Math.PI/10).toString(16);
>> var i = parseInt(s, 16);
>> var f = (s.match(/\.([\da-f]{1,198})/i) || [, "0"])[1];
> ___________________________________^^^____________________
>
> There's no need to trim f to 198 chars:

Not in this example, but for the general case without an adaptive algorithm.

> Math.pow(16, n) overflows at n === 256, not @ 199.

But parseInt(s, 36) "overflows" at more than 198 consecutive "z"s in s.


PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann

Ry Nohryb

unread,
May 30, 2010, 4:15:56 PM5/30/10
to
On May 30, 8:57 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Ry Nohryb wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> (...)
>
> >> var s = (-Math.PI/10).toString(16);
> >> var i = parseInt(s, 16);
> >> var f = (s.match(/\.([\da-f]{1,198})/i) || [, "0"])[1];
> > ___________________________________^^^____________________
>
> > There's no need to trim f to 198 chars:
>
> Not in this example, but for the general case without an adaptive algorithm.
>
> > Math.pow(16, n) overflows at n === 256, not @ 199.
>
> But parseInt(s, 36) "overflows" at more than 198 consecutive "z"s in s.

The fractional part can never be > ( the divisor -1 ), that's why
you've got to look at the divisor (Math.pow(base, len) instead, as I
did in my "take 3", and adjust len accordingly (to both the base and
the fractional part string length):

/* Tested in Safari, Chrome, Opera & FF */
String.prototype.toFP= function (base, n, r, w, div) {
if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
n= this.split('.');
if (isFinite(r= parseInt(n[0], base))) {
if (w= (n= n[1]).length) {
/*trim until it's finite*/
while (!isFinite(div= Math.pow(base, w))) w--;
r+= (r<0 ? -1:1)* parseInt(n.substr(0, w), base)/ div;
}
}
return r;
};

for (var base=2; base <37; base++) console.log([base,
Math.PI.toString(base).toFP(base)])

--> === Math.PI
--
Jorge.

Dr J R Stockton

unread,
May 30, 2010, 12:28:06 PM5/30/10
to
In comp.lang.javascript message <Xns9D87B782...@194.109.133.242>
, Sat, 29 May 2010 16:02:20, Evertjan. <exjxw.ha...@interxnl.net>
posted:

>Dr J R Stockton wrote on 28 mei 2010 in comp.lang.javascript:
>
>> In comp.lang.javascript message <Xns9D85CE44...@194.109.133.242>
>> , Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.ha...@interxnl.net>
>> posted:

>However we were [or at least I was] just contemplating a general function


>for conversion of any root[1..36] floating point string to number value.

Remember to include isNaN & !isFinite testing.

>Such functions are much safer explicit than embedded,

Sometimes. The advantage of an embedded bug is that someone else is
more likely to find it first, and get it fixed.

Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
radix.

>btw: in root 1 only the zero value can be expressed.

Eh?

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQqish topics, acronyms & links;
Astro stuff via astron-1.htm, gravity0.htm ; quotings.htm, pascal.htm, etc.
No Encoding. Quotes before replies. Snip well. Write clearly. Don't Mail News.

Ry Nohryb

unread,
May 30, 2010, 7:12:05 PM5/30/10
to
On May 30, 10:15 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
>
> /* Tested in Safari, Chrome, Opera & FF */
>
> String.prototype.toFP= function (base, n, r, w, div) {
>   if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
>   n= this.split('.');
>   if (isFinite(r= parseInt(n[0], base))) {
>     if (w= (n= n[1]).length) {
>       /*trim until it's finite*/
>       while (!isFinite(div= Math.pow(base, w))) w--;
>       r+= (r<0 ? -1:1)* parseInt(n.substr(0, w), base)/ div;
>     }
>   }
>   return r;
> };


****** BUG FIX:

/* Tested in Safari, Chrome, Opera & FF */

String.prototype.toFP= function (base, n, r, w, div, s) {


if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
n= this.split('.');
if (isFinite(r= parseInt(n[0], base))) {

if (n[1] && (w= n[1].length)) {
/*trim until div is finite*/


while (!isFinite(div= Math.pow(base, w))) w--;

/*Tests sign properly for -0.xxxx*/
s= (r || parseInt(n[0]+ "1", base)) < 0 ? -1:1;
r+= s* parseInt(n[1].substr(0, w), base)/ div;
}
}
return r;
};

"ff".toFP(16) /* integer input no longer throws */
--> 255

(-Math.PI/10).toString(16).toFP(16) /* proper sign detection */
--> -0.3141592653589793
--
Jorge.

David Mark

unread,
May 30, 2010, 7:49:58 PM5/30/10
to
On May 30, 12:28 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:
> In comp.lang.javascript message <Xns9D87B7820AFF3eej...@194.109.133.242>
> , Sat, 29 May 2010 16:02:20, Evertjan. <exjxw.hannivo...@interxnl.net>

> posted:
>
> >Dr J R Stockton wrote on 28 mei 2010 in comp.lang.javascript:
>
> >> In comp.lang.javascript message <Xns9D85CE4464FCFeej...@194.109.133.242>
> >> , Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.hannivo...@interxnl.net>

> >> posted:
> >However we were [or at least I was] just contemplating a general function
> >for conversion of any root[1..36] floating point string to number value.
>
> Remember to include isNaN & !isFinite testing.
>
> >Such functions are much safer explicit than embedded,
>
> Sometimes.  The advantage of an embedded bug is that someone else is
> more likely to find it first, and get it fixed.
>
> Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
> radix.

Not from what I've seen (just tested it). I just happened to be
working on some code that relies on toString to work with a radix and
your comment was a real spit-take moment.

Which Opera 10.10 are you testing?

Thomas 'PointedEars' Lahn

unread,
May 30, 2010, 8:34:01 PM5/30/10
to
David Mark wrote:

> Dr J R Stockton wrote:
>> Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
>> radix.

JFTR: Number.toString !== Number.prototype.toString.



> Not from what I've seen (just tested it). I just happened to be
> working on some code that relies on toString to work with a radix and
> your comment was a real spit-take moment.
>
> Which Opera 10.10 are you testing?

WFM, too. (128).toString(36) === "3k" in "Opera/9.80 (X11; Linux i686; U;
en) Presto/2.2.15 Version/10.10" (Build 4742) and "Opera/9.80 (Windows NT
5.1; U; en) Presto/2.2.15 Version/10.10" (Build 1893).

David Mark

unread,
May 30, 2010, 9:14:03 PM5/30/10
to
On May 30, 8:34 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > Dr J R Stockton wrote:
> >> Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
> >> radix.
>
> JFTR: Number.toString !== Number.prototype.toString.

Right. Number.toString === Function.prototype.toString

>
> > Not from what I've seen (just tested it).  I just happened to be
> > working on some code that relies on toString to work with a radix and
> > your comment was a real spit-take moment.
>
> > Which Opera 10.10 are you testing?
>
> WFM, too.  (128).toString(36) === "3k" in "Opera/9.80 (X11; Linux i686; U;
> en) Presto/2.2.15 Version/10.10" (Build 4742) and "Opera/9.80 (Windows NT
> 5.1; U; en) Presto/2.2.15 Version/10.10" (Build 1893).
>

I'd be pretty shocked if it didn't. Would be a hell of a regression.

Evertjan.

unread,
May 31, 2010, 3:15:33 AM5/31/10
to
Dr J R Stockton wrote on 30 mei 2010 in comp.lang.javascript:

>>btw: in root 1 only the zero value can be expressed.

radix for Latinists?

> Eh?

How would you express 5 or 0.7 ?

Ry Nohryb

unread,
May 31, 2010, 5:12:07 AM5/31/10
to
On May 30, 6:28 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:
> (...)

> Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
> radix.

There's a bug in Safaris also:

(Math.PI/10000).toString(anyBase)
--> "0"
--
Jorge.

Evertjan.

unread,
May 31, 2010, 5:32:46 AM5/31/10
to
Ry Nohryb wrote on 31 mei 2010 in comp.lang.javascript:

> String.prototype.toFP= function (base, n, r, w, div, s) {
> if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
> n= this.split('.');
> if (isFinite(r= parseInt(n[0], base))) {
> if (n[1] && (w= n[1].length)) {
> /*trim until div is finite*/
> while (!isFinite(div= Math.pow(base, w))) w--;
> /*Tests sign properly for -0.xxxx*/
> s= (r || parseInt(n[0]+ "1", base)) < 0 ? -1:1;


s= parseInt(n[0]+ '1', base)<0 ? -1:1;


> r+= s* parseInt(n[1].substr(0, w), base)/ div;
> }
> }
> return r;
>};
>

--

Evertjan.

unread,
May 31, 2010, 5:49:30 AM5/31/10
to
Evertjan. wrote on 31 mei 2010 in comp.lang.javascript:

> Ry Nohryb wrote on 31 mei 2010 in comp.lang.javascript:
>
>> String.prototype.toFP= function (base, n, r, w, div, s) {
>> if (/[^0-9a-z\.+-]/i.test(this)) return NaN;
>> n= this.split('.');
>> if (isFinite(r= parseInt(n[0], base))) {
>> if (n[1] && (w= n[1].length)) {
>> /*trim until div is finite*/
>> while (!isFinite(div= Math.pow(base, w))) w--;
>> /*Tests sign properly for -0.xxxx*/
>> s= (r || parseInt(n[0]+ "1", base)) < 0 ? -1:1;
>
>
> s= parseInt(n[0]+ '1', base)<0 ? -1:1;

Or even:

s= n[0][0]=='-' ?-1 :1;

Stefan Weiss

unread,
May 31, 2010, 7:05:48 AM5/31/10
to
On 31/05/10 09:15, Evertjan. wrote:
> Dr J R Stockton wrote on 30 mei 2010 in comp.lang.javascript:
>
>>>btw: in root 1 only the zero value can be expressed.
>
> radix for Latinists?
>
>> Eh?
>
> How would you express 5 or 0.7 ?

In a unary system it's more usual to count like this:

1
11
111
1111

Not all values can be expressed this way (for example, 0 or 1.05), but
at least you get more values that just the zero.


--
stefan

Evertjan.

unread,
May 31, 2010, 7:29:24 AM5/31/10
to
Evertjan. wrote on 31 mei 2010 in comp.lang.javascript:

> Evertjan. wrote on 31 mei 2010 in comp.lang.javascript:
>
>> Ry Nohryb wrote on 31 mei 2010 in comp.lang.javascript:
>>
>>> String.prototype.toFP= function (base, n, r, w, div, s) {
>>> if (/[^0-9a-z\.+-]/i.test(this)) return NaN;


This test is not enough now, meseems:

a = '12345abc.5def'
document.write((a.toFP(10)) // 12345.0005

use:

var re = base>10 ?'a-'+String.fromCharCode(86+base) :'';
re = new RegExp('[^0-9'+re+'\.+-]','i');
if (re.test(this)) return NaN;

and add:

if (/[+-]/.test(this.substr(1))) return NaN; //+- must be in position 0
if (this.replace(/[^\.]+/g,'').length>1) return NaN; // count of . <=1

Evertjan.

unread,
May 31, 2010, 7:50:03 AM5/31/10
to
Stefan Weiss wrote on 31 mei 2010 in comp.lang.javascript:

> In a unary system it's more usual to count like this:
>
> 1
> 11
> 111
> 1111
>
> Not all values can be expressed this way (for example, 0 or 1.05), but
> at least you get more values that just the zero.

I do not agree in the sense of radixed position dependent strings.

You are mixing position dependent and position independent notation,
and not comparing radix notations.

Your unary system is not based on the extrapolation of such position
dependent numeric string notation.
You even erroneously introduce a position by your right justification.
In your system the zero is an empty string, btw.

Hebrew numbers, while having characters for 1..9 10 20 30 etc, is also
totally position independent, while Latin I II III IV is semi-dependent.
In such systems the zero cannot exist for logical reasons.

So I hold that "radix 1" notation only can specify the zero value, since
that is there only character available, even though a theoretical position
notation exists.

The "radix 0" notation is even more esoteric, as all positions can only be
empty. This does not mean that an empty string is zero, btw.

Stefan Weiss

unread,
May 31, 2010, 8:42:09 AM5/31/10
to
On 31/05/10 13:50, Evertjan. wrote:
> Stefan Weiss wrote on 31 mei 2010 in comp.lang.javascript:
>
>> In a unary system it's more usual to count like this:
>>
>> 1
>> 11
>> 111
>> 1111
>>
>> Not all values can be expressed this way (for example, 0 or 1.05), but
>> at least you get more values that just the zero.
>
> I do not agree in the sense of radixed position dependent strings.
>
> You are mixing position dependent and position independent notation,
> and not comparing radix notations.

It was not meant to be an extension of the radix notation; I only said
it was a more usual notation for systems with only one symbol.

> Your unary system is not based on the extrapolation of such position
> dependent numeric string notation.
> You even erroneously introduce a position by your right justification.
> In your system the zero is an empty string, btw.

I never mentioned strings - the concept of an empty string doesn't make
sense on paper, or on the wall of a prison cell.
If the unary notation I used is position independent, how can right or
left justification be an error?

> The "radix 0" notation is even more esoteric, as all positions can only be
> empty. This does not mean that an empty string is zero, btw.

Right, and now let's try fractional radices!


--
stefan

Evertjan.

unread,
May 31, 2010, 9:14:57 AM5/31/10
to
Stefan Weiss wrote on 31 mei 2010 in comp.lang.javascript:

> I never mentioned strings

Implicitly, the notation of a number in a certain radix MUST BE in a
string.

> - the concept of an empty string doesn't
> make sense on paper, or on the wall of a prison cell.

Oh, but it does, OT as we are talking Javascript number values.

The prisoner has no dilemma in carving the first vertical stroke ony after
his first day in his cell. Thae absense of that stroke is a fair definition
of zero completed days.

> If the unary notation I used is position independent, how can right or
> left justification be an error?

You sowed a right justification, implying there rightmost value to be the
first, either in error, or, if you deny that, in falsehood?


>> The "radix 0" notation is even more esoteric, as all positions can
>> only be empty. This does not mean that an empty string is zero, btw.
>
> Right, and now let's try fractional radices!

RIGHT, then we are LEFT with far more interesting negative radices.

Would they count as uprooted free radicals,
the oxigen of string notation of numbers?

Or is this only string theory?

Ry Nohryb

unread,
May 31, 2010, 9:44:24 AM5/31/10
to
On May 31, 1:29 pm, "Evertjan." <exjxw.hannivo...@interxnl.net> wrote:
>
> This test is not enough now, meseems:
>
> a = '12345abc.5def'
> document.write((a.toFP(10)) // 12345.0005
>
> use:
>
> var re = base>10 ?'a-'+String.fromCharCode(86+base) :'';
> re = new RegExp('[^0-9'+re+'\.+-]','i');
> if (re.test(this)) return NaN;
>
> and add:
>
> if (/[+-]/.test(this.substr(1))) return NaN; //+- must be in position 0
> if (this.replace(/[^\.]+/g,'').length>1) return NaN; // count of . <=1

Well, yes, the inputs ought to be validated. Both the base parameter
and the 'this' string.

Funny thing is that once you add the -ugly- regExp to test the
structure and its contents, it's easy to use it to capture the
validated parts, and then the rest becomes even simpler than before
( ~8 LOC ):

String.prototype.toFP= function (base, n, r, w, div) {
//20100531 by jo...@jorgechamorro.com

/* check that base is in range and an integer */
if ((base < 2) || (base > 36) || (base % 1)) return NaN;

/* get the digits that are valid for this base */
validDigits= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);

/* validate structure and contents of the input str : */
/* ^ (optional) whitespace + (optional) a single char [-+] */
/* + (non-optional) 1 or more validDigits + (optional) a point */
/* + (optional) more validDigits + (optional) whitespace $ */
n= "^\\s{0,}([-+]{0,1})(["+ validDigits+ "]{1,})[.]{0,1}(["+
validDigits+ "]{0,})\\s{0,}$";

/* exec n on 'this' now, case-insensitively, and reuse n*/
if (!(n= new RegExp(n, "i").exec(this))) return NaN;

/* got captured : */
/* n[1]= sign, n[2]=integer part, n[3]= fractional part */

if (isFinite(r= parseInt(n[2], base)) && (w= n[3].length)) {
/* trim until div is finite */


while (!isFinite(div= Math.pow(base, w))) w--;

r+= parseInt(n[3].substr(0, w), base)/ div;
}

/* sign is one of "1" or "+1" or "-1" */
return (n[1]+ "1")* r;
};

--
Jorge.

Evertjan.

unread,
May 31, 2010, 10:14:52 AM5/31/10
to
Ry Nohryb wrote on 31 mei 2010 in comp.lang.javascript:

> /* get the digits that are valid for this base */
> validDigits= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);

nice!



> /* validate structure and contents of the input str : */
> /* ^ (optional) whitespace + (optional) a single char [-+] */
> /* + (non-optional) 1 or more validDigits + (optional) a point */
> /* + (optional) more validDigits + (optional) whitespace $ */
> n= "^\\s{0,}([-+]{0,1})(["+ validDigits+ "]{1,})[.]{0,1}(["+
> validDigits+ "]{0,})\\s{0,}$";

This would fail for 'pointfractions', like ".56ab" and "-.2"

In short:

n='^\\s*([-+]?)(['+validDigits+']+)\\.?(['+validDigits+']?)\\s*$';


However, to allow for such pointfractions would need something like this:

n1='^\\s*([-+]?)(['+validDigits+']+)\\.?(['+validDigits+']?)\\s*$';
n2='^\\s*([-+]?)()\\.(['+validDigits+']?)\\s*$';

n = n1 + '|' + n2

or

n1 = '^\\s*([-+]?)'
n2a = '(['+validDigits+']+)\\.?'
n2b = '()\\.'
n3 = '(['+validDigits+']?)\\s*$';

n = n1 + '(?:' + n2a + '|' + n2b + ')' + n3

not tested.


> /* exec n on 'this' now, case-insensitively, and reuse n*/
> if (!(n= new RegExp(n, "i").exec(this))) return NaN;

> /* got captured : */
> /* n[1]= sign, n[2]=integer part, n[3]= fractional part */

David Mark

unread,
May 31, 2010, 10:44:08 AM5/31/10
to
On May 31, 5:12 am, Ry Nohryb <jo...@jorgechamorro.com> wrote:
> On May 30, 6:28 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
> wrote:
>
> > (...)
> > Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
> > radix.
>
> There's a bug in Safaris also:
>

Also? It's been demonstrated that there is no such bug in Opera
10.10.

Ry Nohryb

unread,
May 31, 2010, 10:55:48 AM5/31/10
to

Hmmm, I think I just have to make that part optional in the regexp
({0,} instead of {1,}), and guard n[2] with || "0" in the call to
parseInt() :

String.prototype.toFP= function (base, n, r, w, div) {
//20100531 by jo...@jorgechamorro.com

/* check that base is in range and an integer */
if ((base < 2) || (base > 36) || (base % 1)) return NaN;

/* get the digits that are valid for this base */
validDigits= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);

/* validate structure and contents of the input str : */


/* ^ (optional) whitespace + (optional) a single char [-+] */
/* + (non-optional) 1 or more validDigits + (optional) a point */
/* + (optional) more validDigits + (optional) whitespace $ */

n= "^\\s{0,}([-+]{0,1})(["+ validDigits+ "]{0,})[.]{0,1}(["+


validDigits+ "]{0,})\\s{0,}$";

/* exec n on 'this' now, case-insensitively, and reuse n*/


if (!(n= new RegExp(n, "i").exec(this))) return NaN;

/* got captured : */
/* n[1]= sign, n[2]=integer part, n[3]= fractional part */

if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {


/* trim until div is finite */
while (!isFinite(div= Math.pow(base, w))) w--;
r+= parseInt(n[3].substr(0, w), base)/ div;
}

/* sign is one of "1" or "+1" or "-1" */
return (n[1]+ "1")* r;
};

"-.8".toFP(10)
--> -0.8
--
Jorge.

Stefan Weiss

unread,
May 31, 2010, 11:16:44 AM5/31/10
to
On 31/05/10 16:55, Ry Nohryb wrote:
> On May 31, 4:14 pm, "Evertjan." <exjxw.hannivo...@interxnl.net> wrote:
>> This would fail for 'pointfractions', like ".56ab" and "-.2"
...

> Hmmm, I think I just have to make that part optional in the regexp
> ({0,} instead of {1,}), and guard n[2] with || "0" in the call to
> parseInt() :

Since you like short code:

{0,} is the same as *
{1,} is the same as +

:)


--
stefan

Evertjan.

unread,
May 31, 2010, 12:54:44 PM5/31/10
to
Stefan Weiss wrote on 31 mei 2010 in comp.lang.javascript:

> Since you like short code:
>
> {0,} is the same as *
> {1,} is the same as +

and {0,1} is ?

Ry Nohryb

unread,
May 31, 2010, 1:07:40 PM5/31/10
to
On May 31, 5:16 pm, Stefan Weiss <krewech...@gmail.com> wrote:
>
> Since you like short code:
>
>   {0,} is the same as *
>   {1,} is the same as +
>
> :)

Yes, but, don't you find their -the regExps'- syntax sufficiently
confusing and unintelligible enough without the shortcuts ? Whose sick
mind invented such an ugly thing ? :-)
--
Jorge.

Ry Nohryb

unread,
May 31, 2010, 1:09:33 PM5/31/10
to
On May 31, 6:54 pm, "Evertjan." <exjxw.hannivo...@interxnl.net> wrote:
> Stefan Weiss wrote on 31 mei 2010 in comp.lang.javascript:
>
> > Since you like short code:
>
> >   {0,} is the same as *
> >   {1,} is the same as +
>
> and {0,1} is ?

That looks like a question, hahaha.
--
Jorge.

Ry Nohryb

unread,
May 31, 2010, 1:23:35 PM5/31/10
to
On May 31, 4:55 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
> (...)

>   /* get the digits that are valid for this base */
>   validDigits= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);
> (...)

Oops, forgot to declare "validDigits". What if I just reuse "n"
again ?

String.prototype.toFP= function (base, n, r, w, div) {
//20100531 by jo...@jorgechamorro.com

/* check that base is in range and an integer */
if ((base < 2) || (base > 36) || (base % 1)) return NaN;

/* get the digits that are valid for this base */

n= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);

/* validate structure and contents of the input str : */
/* ^ (optional) whitespace + (optional) a single char [-+] */

/* + (optional) 0 or more validDigits + (optional) a point */


/* + (optional) more validDigits + (optional) whitespace $ */

n= "^\\s{0,}([-+]{0,1})(["+ n+ "]{0,})[.]{0,1}(["+ n+ "]{0,})\
\s{0,}$";

/* exec n on 'this' now, case-insensitively, and reuse n*/
if (!(n= new RegExp(n, "i").exec(this))) return NaN;

/* by now we've got captured, cleaned-up and validated : */


/* n[1]= sign, n[2]=integer part, n[3]= fractional part */

if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {
/* trim until div is finite */
while (!isFinite(div= Math.pow(base, w))) w--;
r+= parseInt(n[3].substr(0, w), base)/ div;
}

/* sign is one of "1" or "+1" or "-1" */
return (n[1]+ "1")* r };

"\t -.z\r".toFP(36).toString(36)
--> "-0.z"
--
Jorge.

Ry Nohryb

unread,
May 31, 2010, 1:47:57 PM5/31/10
to
On May 31, 7:23 pm, Ry Nohryb <jo...@jorgechamorro.com> wrote:
>
> (...)

W/o the comments it's really just only 11 LOCs :

String.prototype.toFP= function (base, n, r, w, div) {

if ((base < 2) || (base > 36) || (base % 1)) return NaN;

n= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);
n= "^\\s{0,}([-+]{0,1})(["+n+"]{0,})[.]{0,1}(["+n+"]{0,})\\s{0,}$";


if (!(n= new RegExp(n, "i").exec(this))) return NaN;

if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {


while (!isFinite(div= Math.pow(base, w))) w--;
r+= parseInt(n[3].substr(0, w), base)/ div;
}

return (n[1]+ "1")* r;
};

What other bugs are there left into it ?
Would it be a good idea to memoize the regExps ?
Hey, Pointy, what's its Jorgtropy level ?
--
Jorge.

Dr J R Stockton

unread,
May 31, 2010, 1:34:48 PM5/31/10
to
In comp.lang.javascript message <3459374.h...@PointedEars.de>,
Sun, 30 May 2010 13:30:58, Thomas 'PointedEars' Lahn
<Point...@web.de> posted:

>Dr J R Stockton wrote:
>
>> Thomas 'PointedEars' Lahn posted:
>>> Yes, good catch; we need to consider the sign with addition, e.g.:
>>>
>>> var s = (-Math.PI).toString(16);


>>> var i = parseInt(s, 16);

>>> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>>> var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16, f.length);
>>
>> You need to consider it more effectively, and to test adequately.
>
>Do you know what "quick hack" means?

Generally slovenly working, with a tendency to miss the obvious.

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

Unless you are working with dates, it is better to use j, rather than i,
for a short-term identifier in News. The former is likely, in an
unknown font, to be better distinguishable from other characters; and it
does not excite the attention of a spelling-checker.

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME
Prof Timo Salmi's Usenet Q&A <URL:ftp://garbo.uwasa.fi/pc/link/tsfaqn.zip>
TS FAQs via : http://www.uwasa.fi/~ts/http/ : tsfaq.html quote margin &c.
Jukka Korpela: <URL:http://www.malibutelecom.com/yucca/usenet/dont.html>.

Ry Nohryb

unread,
May 31, 2010, 6:51:12 PM5/31/10
to
On May 31, 7:34 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:
> In comp.lang.javascript message <3459374.heAe9J7...@PointedEars.de>,

>
> >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 would be zero. What's the sign of zero ?
--
Jorge.

Scott Sauyet

unread,
Jun 1, 2010, 9:47:41 AM6/1/10
to
Ry Nohryb <jo...@jorgechamorro.com> wrote:
> W/o the comments it's really just only 11 LOCs :

Quite unreadable LOC, I'm afraid.

> String.prototype.toFP= function (base, n, r, w, div) {
>
>   if ((base < 2) || (base > 36) || (base % 1)) return NaN;
>
>   n= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);
>   n= "^\\s{0,}([-+]{0,1})(["+n+"]{0,})[.]{0,1}(["+n+"]{0,})\\s{0,}$";
>   if (!(n= new RegExp(n, "i").exec(this))) return NaN;
>
>   if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {
>     while (!isFinite(div= Math.pow(base, w))) w--;
>     r+= parseInt(n[3].substr(0, w), base)/ div;
>   }
>
>   return (n[1]+ "1")* r;
>
> };
>
> What other bugs are there left into it ?

If I find some time this evening, I'll look into the accuracy. I'm
curious as to whether something like this would be more precise,
although it would clearly not perform as well:

var parseFloat = (function() {
var origPF = parseFloat,
allDigits = "0123456789abcdefghijklmnopqrstuvwxyz",
regexes = {},
getRegex = function(base) {
if (!regexes[base]) {
var digits = allDigits.substring(0, base);
regexes[base] = new RegExp("(^[\\-\\+]?)([" + digits +
"]*)(?:\.([" + digits + "]*))?$");
}
return regexes[base];
},
parseFraction = function(str, base) {
if (!str) return 0;
var digits = str.split(""), total = 0;
for (var i = digits.length; i--;) {
total += allDigits.indexOf(digits[i]);
total /= base;
}
return total;
};

return function (str, base) {
if (!base || base == 10) {
return origPF(str);


}
if ((base < 2) || (base > 36) || (base % 1)) return NaN;

str = str.toString().toLowerCase();
var regex = getRegex(base),
match = regex.exec(str);
if (!match) return NaN;
return ((match[1] == "-") ? -1 : 1) * (
parseInt(match[2], base) + parseFraction(match[3], base)
);
};
}());


> Would it be a good idea to memoize the regExps ?

If you're concerned about performance, then yes. They depend only on
the (35 possible) bases used.

--
Scott

Thomas 'PointedEars' Lahn

unread,
Jun 1, 2010, 11:58:37 AM6/1/10
to
Dr J R Stockton wrote:

> Thomas 'PointedEars' Lahn posted:
>> Dr J R Stockton wrote:
>>> Thomas 'PointedEars' Lahn posted:
>>>> Yes, good catch; we need to consider the sign with addition, e.g.:
>>>>
>>>> var s = (-Math.PI).toString(16);
>>>> var i = parseInt(s, 16);
>>>> var f = (s.match(/\.([\da-f]+)/i) || [, "0"])[1];
>>>> var n = i + (i < 0 ? -1 : 1) * parseInt(f, 16) / Math.pow(16,
>>>> f.length);
>>>
>>> You need to consider it more effectively, and to test adequately.
>> Do you know what "quick hack" means?
>
> Generally slovenly working, with a tendency to miss the obvious.

No. Quick hack refers to code that is largely untested, if that. It is
therefore unreasonable to insist that it should have been (properly) tested
(when it fails to accomplish the intended task).

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

Dr J R Stockton

unread,
Jun 1, 2010, 2:20:38 PM6/1/10
to
In comp.lang.javascript message <9ec0357f-f6f7-4680-829c-bc4403160303@z1
5g2000prh.googlegroups.com>, Sun, 30 May 2010 16:49:58, David Mark
<dmark....@gmail.com> posted:

>On May 30, 12:28�pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
>wrote:
>> In comp.lang.javascript message <Xns9D87B7820AFF3eej...@194.109.133.242>
>> , Sat, 29 May 2010 16:02:20, Evertjan. <exjxw.hannivo...@interxnl.net>
>> posted:
>>
>> >Dr J R Stockton wrote on 28 mei 2010 in comp.lang.javascript:
>>
>> >> In comp.lang.javascript message <Xns9D85CE4464FCFeej...@194.109.133.242>
>> >> , Thu, 27 May 2010 18:16:34, Evertjan. <exjxw.hannivo...@interxnl.net>
>> >> posted:
>> >However we were [or at least I was] just contemplating a general function
>> >for conversion of any root[1..36] floating point string to number value.
>>
>> Remember to include isNaN & !isFinite testing.
>>
>> >Such functions are much safer explicit than embedded,
>>
>> Sometimes. �The advantage of an embedded bug is that someone else is
>> more likely to find it first, and get it fixed.


>>
>> Opera 10.10, but not Opera 10.53 : Number.toString(radix) ignores
>> radix.
>

>Not from what I've seen (just tested it). I just happened to be
>working on some code that relies on toString to work with a radix and
>your comment was a real spit-take moment.
>
>Which Opera 10.10 are you testing?

Version 10.10
Build 1893
Platform Win32
System Windows XP
Java Sun Java Runtime Environment version 1.6
XHTML+Voice Plug-in not loaded
Browser identification
Opera/9.80 (Windows NT 5.1; U; en-GB) Presto/2.2.15 Version/10.10

Example :
Math.random().toString(2)
always returns a string between 0.0 and 0.999999 ...
in which, after the "0.", on average only about 10% of the characters
are "0" and only about another 10% are "1" - about 80% are in "2"-"9".


The same test in my Opera 10.53 gives strings consisting entirely of "0"
& "1" after the "0.", except that the last character is quite often a
"2".

Similar (last digit = radix) - has been seen throughout radix 2 to 7,
and 9, and 11 (get ":"). Radix 36 has been seen to give ":" and "{".

The correctness of base 8, and the difference seen at base 32, could
have been due to imperfection in Math.random. So I've tried
Math.sqrt(Math.random()) with clearer results : all below radix 10 are
similarly defective, and all above radix 10 are similar with the
addition of ":".

It should be noted that, if my laptop and its Opera are not corrupt,
this test funds something imperfect about Opera 10.53 Math.random, since
Math.sqrt should have made no difference AFAICS.

The code lists, for each radix R, all the final digits observed in 1e6
tests of Math.sqrt(Math.random()).toString(R). Base 10 is correct; all
others have an extra digit; all above 10 have a colon.


B = []
for (R=2 ; R<=36 ; R++) { A = []
for (J=0 ; J<1e6 ; J++) {
S = Math.sqrt(Math.random()).toString(R)
L = S.length
T = S[L-1]
A[T.charCodeAt(0)] = T }
B.push(R + "\t" + A.join("")) }

document.write("<pre>" + B.join("\n") + "<\/pre>")


2 12
3 123
4 1234
5 12345
6 123456
7 1234567
8 12345678
9 123456789
10 123456789
11 123456789:ab
12 123456789:abc
13 123456789:abcd
14 123456789:abcde
15 123456789:abcdef
16 123456789:abcdefg
17 123456789:abcdefgh
18 123456789:abcdefghi
19 123456789:abcdefghij
20 123456789:abcdefghijk
21 123456789:abcdefghijkl
22 123456789:abcdefghijklm
23 123456789:abcdefghijklmn
24 123456789:abcdefghijklmno
25 123456789:abcdefghijklmnop
26 123456789:abcdefghijklmnopq
27 123456789:abcdefghijklmnopqr
28 123456789:abcdefghijklmnopqrs
29 123456789:abcdefghijklmnopqrst
30 123456789:abcdefghijklmnopqrstu
31 123456789:abcdefghijklmnopqrstuv
32 123456789:abcdefghijklmnopqrstuvw
33 123456789:abcdefghijklmnopqrstuvwx
34 123456789:abcdefghijklmnopqrstuvwxy
35 123456789:abcdefghijklmnopqrstuvwxyz
36 123456789:abcdefghijklmnopqrstuvwxyz{

A run takes at most a few minutes on a recent PC.

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Proper <= 4-line sig. separator as above, a line exactly "-- " (RFCs 5536/7)
Do not Mail News to me. Before a reply, quote with ">" or "> " (RFCs 5536/7)

Dr J R Stockton

unread,
Jun 1, 2010, 11:38:29 AM6/1/10
to
In comp.lang.javascript message <Xns9D89A54A...@194.109.133.242>
, Mon, 31 May 2010 14:14:52, Evertjan. <exjxw.ha...@interxnl.net>
posted:

>
>This would fail for 'pointfractions', like ".56ab" and "-.2"
>

Those should not be written - see IUPAP-25 / SUNAMCO 87-1, section
1.3.2.

Query : what does one call the dot in 123.456 if the radix is unknown?

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05 IE 7.


Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.

Command-prompt MiniTrue is useful for viewing/searching/altering files. Free,
DOS/Win/UNIX now 2.0.6; see <URL:http://www.merlyn.demon.co.uk/pc-links.htm>.

Ry Nohryb

unread,
Jun 2, 2010, 8:29:39 AM6/2/10
to

I like that parseFraction() of yours, it's awesome. Good idea. In
order to test it agains the .toFP algorithm, I've written this: it
loops through all the bases, and converts an increasingly smaller
number i until i !=== [ parseFloat || toFP ](i.toString(base)). The
win is given to the algorithm that fails with a smaller i. The funny
thing is that different browsers give different results (due, I guess,
to differences in .toString(base)), but, in general, your algorithm
WINS (in all but FF):

(Tested on a Mac)

Safari(*) r60462: WINS: toFP(): 5, ParseFloat(): 6
FF3.6.4: WINS: toFP(): 15, ParseFloat(): 9
Chrome 5.0.375.38: WINS: toFP(): 11, ParseFloat(): 16
Opera10.53: WINS: toFP(): 2, ParseFloat(): 4

(*) .toString(base) is broken in Safari.

The test code follows: just copy-paste it, it's a bookmarklet:

javascript:

String.prototype.toFP= (function (regExpCache) {
/* 20100531, by jo...@jorgechamorro.com */

return function (base, n, r, w, div) {


if ((base < 2) || (base > 36) || (base % 1)) return NaN;

if (!(n= regExpCache[base])) {


n= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);
n= "^\\s{0,}([-+]{0,1})(["+n+"]{0,})[.]{0,1}(["+n+"]{0,})\\s{0,}$";

regExpCache[base]= n= new RegExp(n, "i");
}

if (!(n= n.exec(this))) return NaN;

if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {
while (!isFinite(div= Math.pow(base, w))) w--;
r+= parseInt(n[3].substr(0, w), base)/ div;
}
return (n[1]+ "1")* r;
};

})([]);

(function test () {
var parseFloatScore= 0;
var toFPScore= 0;
console.log("[ Base, toFP(base), parseFloat(base), winner ]");
for (var base= 2; base < 37; base ++) {
var i= 1e-1;
var r= [base];
while ( i && (i === i.toString(base).toFP(base)) ) {
var iSave= i;
i*= 1e-1;
}
r.push(iSave);
i= 1e-1;
while ( i && (i === parseFloat(i.toString(base), base)) ) {
var iSave= i;
i*= 1e-1;
}
r.push(iSave);
if (r[1] === r[2]) r.push("===");
else r.push("WINNER: "+ ( r[1] > r[2] ?
(parseFloatScore++, "ParseFloat()") :
(toFPScore++, "toFP()") ));
console.log(r);
}
console.log("WINS: toFP(): "+ toFPScore+ ", ParseFloat(): "+
parseFloatScore);
})();


************ Here's the sample output in Chrome:

[ Base, toFP(base), parseFloat(base), winner ]
[2, 1.0000000000000164e-292, 1e-323, "WINNER: ParseFloat()"]
[3, 1e-323, 1e-323, "==="]
[4, 1.0000000000000163e-291, 1e-323, "WINNER: ParseFloat()"]
[5, 1e-323, 0.0010000000000000002, "WINNER: toFP()"]
[6, 0.010000000000000002, 0.010000000000000002, "==="]
[7, 0.010000000000000002, 0.1, "WINNER: toFP()"]
[8, 1.0000000000000164e-292, 1e-323, "WINNER: ParseFloat()"]
[9, 1e-323, 1e-323, "==="]
[10, 0.0010000000000000002, 1e-323, "WINNER: ParseFloat()"]
[11, 1e-323, 0.010000000000000002, "WINNER: toFP()"]
[12, 0.010000000000000002, 0.010000000000000002, "==="]
[13, 0.010000000000000002, 0.00010000000000000003, "WINNER:
ParseFloat()"]
[14, 0.00010000000000000003, 0.1, "WINNER: toFP()"]
[15, 0.1, 1.0000000000000005e-9, "WINNER: ParseFloat()"]
[16, 1.0000000000000163e-291, 1e-323, "WINNER: ParseFloat()"]
[17, 1e-323, 0.0010000000000000002, "WINNER: toFP()"]
[18, 0.010000000000000002, 0.00010000000000000003, "WINNER:
ParseFloat()"]
[19, 0.00010000000000000003, 0.00010000000000000003, "==="]
[20, 0.1, 0.0010000000000000002, "WINNER: ParseFloat()"]
[21, 0.010000000000000002, 0.0010000000000000002, "WINNER:
ParseFloat()"]
[22, 0.0010000000000000002, 0.010000000000000002, "WINNER: toFP()"]
[23, 0.010000000000000002, 0.000010000000000000004, "WINNER:
ParseFloat()"]
[24, 0.000010000000000000004, 0.000010000000000000004, "==="]
[25, 0.000010000000000000004, 1.0000000000000005e-7, "WINNER:
ParseFloat()"]
[26, 1.0000000000000005e-7, 0.00010000000000000003, "WINNER: toFP()"]
[27, 0.00010000000000000003, 0.0010000000000000002, "WINNER: toFP()"]
[28, 0.1, 0.1, "==="]
[29, 0.1, 0.1, "==="]
[30, 0.010000000000000002, 1.0000000000000006e-12, "WINNER:
ParseFloat()"]
[31, 1.0000000000000006e-12, 0.0000010000000000000004, "WINNER:
toFP()"]
[32, 1.0000000000000163e-291, 1e-323, "WINNER: ParseFloat()"]
[33, 1e-323, 1.0000000000000005e-9, "WINNER: toFP()"]
[34, 1.0000000000000005e-9, 0.0000010000000000000004, "WINNER:
toFP()"]
[35, 0.0000010000000000000004, 1.0000000000000006e-12, "WINNER:
ParseFloat()"]
[36, 0.1, 0.00010000000000000003, "WINNER: ParseFloat()"]
WINS: toFP():11, ParseFloat(): 16

> > Would it be a good idea to memoize the regExps ?
>
> If you're concerned about performance, then yes.  They depend only on
> the (35 possible) bases used.

Well done. toFP() now memoizes them too :-)
--
Jorge.

Evertjan.

unread,
Jun 2, 2010, 9:57:19 AM6/2/10
to
Dr J R Stockton wrote on 01 jun 2010 in comp.lang.javascript:

> Query : what does one call the dot in 123.456 if the radix is unknown?

A dot?

[In your above example, rhe radix is only partly unknown,
as it must be between 7 and 36 inclusive.]

A fraction delimiter?

[this is better,
as there is no unanimity about what character should be used.]

Scott Sauyet

unread,
Jun 2, 2010, 10:08:17 AM6/2/10
to
Ry Nohryb wrote:
> Scott Sauyet wrote:
>> Ry Nohryb wrote:
>>> [ ... ]

>> If I find some time this evening, I'll look into the accuracy.

I'm glad you had a chance to investigate, because I will not have the
time before the weekend.

>> [ ... ]


>>         parseFraction = function(str, base) {
>>           if (!str) return 0;
>>           var digits = str.split(""), total = 0;
>>           for (var i = digits.length; i--;) {
>>             total += allDigits.indexOf(digits[i]);
>>             total /= base;
>>           }
>>           return total;
>>         };

>> [ ... ]

> I like that parseFraction() of yours, it's awesome. Good idea.

Thanks. I'm not sure if it has any practical advantages, but it's at
least fairly clear mathematically.

> In
> order to test it agains the .toFP algorithm, I've written this: it
> loops through all the bases, and converts an increasingly smaller
> number i until i !=== [ parseFloat || toFP ](i.toString(base)). The
> win is given to the algorithm that fails with a smaller i. The funny
> thing is that different browsers give different results (due, I guess,
> to differences in .toString(base)), but, in general, your algorithm
> WINS (in all but FF):

It's an interesting result, but I'm not sure how much that really
tells us about accuracy. It's also not clear to me if

floating point --> string --> floating point

is as good a test as

string --> floating point --> string

It's right now just a gut feeling, and I'm not sure why, but I think
we'd learn more from the latter.

>>> Would it be a good idea to memoize the regExps ?
>
>> If you're concerned about performance, then yes.  They depend only on
>> the (35 possible) bases used.
>
> Well done. toFP() now memoizes them too :-)

For your function, you might want to cache the "w" values as well.

--
Scott

Thomas 'PointedEars' Lahn

unread,
Jun 2, 2010, 12:53:26 PM6/2/10
to
Scott Sauyet wrote:

> Ry Nohryb wrote:


>> Scott Sauyet wrote:
>>> [ ... ]
>>> parseFraction = function(str, base) {
>>> if (!str) return 0;
>>> var digits = str.split(""), total = 0;
>>> for (var i = digits.length; i--;) {
>>> total += allDigits.indexOf(digits[i]);
>>> total /= base;
>>> }
>>> return total;
>>> };
>>> [ ... ]
>
>> I like that parseFraction() of yours, it's awesome. Good idea.
>
> Thanks. I'm not sure if it has any practical advantages, but it's at
> least fairly clear mathematically.

It is clear(er), but it is unfortunately not mathematically sound because we
are dealing with *floating-point* arithmetics here, where precision is
limited (as I indicated in one of first replies to Jorge):

var
b = 3,
e = 4;
x = Math.pow(b, e),
y = Math.pow(b, e + 1);

/*
* JavaScript 1.8.2:
* 0.004115226337448559 0.00411522633744856 false
*/
console.log(1/x/b, 1/y, 1/x/b == 1/y);

PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)

Scott Sauyet

unread,
Jun 2, 2010, 3:03:27 PM6/2/10
to
Thomas 'PointedEars' Lahn wrote:
>Scott Sauyet wrote:
>> Ry Nohryb wrote:
>>> Scott Sauyet wrote:

>>>> [ ... ]
(I should have included this line:)
| var allDigits = "0123456789abcdefghijklmnopqrstuvwxyz",


>>>> parseFraction = function(str, base) {
>>>> if (!str) return 0;
>>>> var digits = str.split(""), total = 0;
>>>> for (var i = digits.length; i--;) {
>>>> total += allDigits.indexOf(digits[i]);
>>>> total /= base;
>>>> }
>>>> return total;
>>>> };
>>>> [ ... ]
>
>>> I like that parseFraction() of yours, it's awesome. Good idea.
>
>> Thanks.  I'm not sure if it has any practical advantages, but it's at
>> least fairly clear mathematically.
>
> It is clear(er), but it is unfortunately not mathematically sound because we
> are dealing with *floating-point* arithmetics here, where precision is

> limited [ ... ]
> [ example elided ]

Yes, I understand that we are dealing with an implementation of
IEEE-754. But I don't see how that makes my algorithm mathematically
unsound. It is certainly not as efficient as the one you used, but I
think it might avoid some rounding issues.

For instance, if parseFloat1 is the function you posted earlier [1]
and parseFloat2 is the one I posted [2], then in JavaScript 1.8.2

parseFloat1("0.r3j6f0mqo4fr3j6f0m", 36).toString(36)

yields "0.r3j6f0mqo3m", whereas

parseFloat2("0.r3j6f0mqo4fr3j6f0m", 36).toString(36))

yields "0.r3j6f0mqo4f", clearly a better approximation.

This approach, though sacrifices the speed of your algorithm. I
haven't done any performance tests, but if you were to alter your
function to cache the results of the regular expressions, I would
guess that your code would run significantly faster than mine -- maybe
not a full order of magnitude, but several times faster, I would
imagine.


[1] <news:4430313.M...@PointedEars.de>
[2] <news:4c7655c5-
e83f-4559-89f...@q23g2000vba.googlegroups.com>

--
Scott

Thomas 'PointedEars' Lahn

unread,
Jun 2, 2010, 4:55:15 PM6/2/10
to
Scott Sauyet wrote:

You are doing *more* floating-point operations, how can you have *less*
rounding issues?



> For instance, if parseFloat1 is the function you posted earlier [1]
> and parseFloat2 is the one I posted [2], then in JavaScript 1.8.2
>
> parseFloat1("0.r3j6f0mqo4fr3j6f0m", 36).toString(36)
>
> yields "0.r3j6f0mqo3m", whereas
>
> parseFloat2("0.r3j6f0mqo4fr3j6f0m", 36).toString(36))
>
> yields "0.r3j6f0mqo4f", clearly a better approximation.

No doubt about that, although I think you have the test case backwards. I
have since tested my approach more thoroughly and accepted that {1,198} is
flawed as it sacrifices too much precision.

You need to compare the return value of yours against one of Jorge's that
works (that in
<99e57eb6-f5c7-410e...@b21g2000vbh.googlegroups.com> returns
NaN with your test case in JavaScript 1.8.2) instead.


PointedEars
--
Danny Goodman's books are out of date and teach practices that are
positively harmful for cross-browser scripting.
-- Richard Cornford, cljs, <cife6q$253$1$8300...@news.demon.co.uk> (2004)

Dr J R Stockton

unread,
Jun 2, 2010, 3:36:56 PM6/2/10
to
In comp.lang.javascript message <1790020.a...@PointedEars.de>,
Tue, 1 Jun 2010 17:58:37, Thomas 'PointedEars' Lahn <Point...@web.de>
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'.

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.

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.


Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.

Thomas 'PointedEars' Lahn

unread,
Jun 3, 2010, 3:43:22 AM6/3/10
to
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.


PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann

Ry Nohryb

unread,
Jun 3, 2010, 9:58:03 AM6/3/10
to
On Jun 2, 9:36 pm, Dr J R Stockton <reply1...@merlyn.demon.co.uk>
wrote:
> (...)

> You so frequently insist that others search the archives; you should do
> so yourself.  The matter was referred to sometime in the years 200x. (...)

Thanks for such a valuable pointer: we'll dig into 10 years of
threads.
--
Jorge.

Ry Nohryb

unread,
Jun 3, 2010, 10:06:29 AM6/3/10
to
On Jun 2, 4:08 pm, Scott Sauyet <scott.sau...@gmail.com> wrote:
> (...)

> It's an interesting result, but I'm not sure how much that really
> tells us about accuracy. (...)

How about this one ?

var exp= -1;
var inc= 1e-1;
var i= inc;

while ( inc && (i === parseFloat(i.toString(base), base)) ) {
var iSave= i;
i+= (inc= Math.pow(10, --exp));
}

--
Jorge.

Scott Sauyet

unread,
Jun 3, 2010, 2:13:42 PM6/3/10
to

By being more precise. Your algorithm seems to throw away more
information than mine. At least a few random tests seem to indicate
so.


>> For instance, if parseFloat1 is the function you posted earlier [1]
>> and parseFloat2 is the one I posted [2], then in JavaScript 1.8.2
>
>>     parseFloat1("0.r3j6f0mqo4fr3j6f0m", 36).toString(36)
>
>> yields "0.r3j6f0mqo3m", whereas
>
>>     parseFloat2("0.r3j6f0mqo4fr3j6f0m", 36).toString(36))
>
>> yields "0.r3j6f0mqo4f", clearly a better approximation.
>
> No doubt about that, although I think you have the test case backwards.  

No, I've posted a test script at

<http://scott.sauyet.com/Javascript/Test/2010-06-03a/>

This case is

<http://scott.sauyet.com/Javascript/Test/2010-06-03a/?
base=36&value=0.r3j6f0mqo4fr3j6f0m>


> I have since tested my approach more thoroughly and accepted that {1,198} is
> flawed as it sacrifices too much precision.

If you have a new version, I can post a new version of that test page
with it, if you like, or you can modify it as you like. The PHP is
at:

<http://scott.sauyet.com/Javascript/Test/2010-06-03a/index.phps>

> You need to compare the return value of yours against one of Jorge's that
> works (that in

> <99e57eb6-f5c7-410e-a40f-07ae48af2...@b21g2000vbh.googlegroups.com> returns


> NaN with your test case in JavaScript 1.8.2) instead.

Jorge's seems to generally agree with yours. Mine will sometimes end
up a closer match to the original string.

--
Scott

Dr J R Stockton

unread,
Jun 4, 2010, 4:06:22 PM6/4/10
to
In comp.lang.javascript message <3200480.O...@PointedEars.de>,
Thu, 3 Jun 2010 09:43:22, Thomas 'PointedEars' Lahn <Point...@web.de>
posted:

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.

Dr J R Stockton

unread,
Jun 15, 2010, 6:41:23 PM6/15/10
to
In comp.lang.javascript message <1J7cUsIS...@invalid.uk.co.demon.me
rlyn.invalid>, Fri, 28 May 2010 20:35:46, Dr J R Stockton
<repl...@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 }

Scott Sauyet

unread,
Jun 16, 2010, 11:30:51 AM6/16/10
to
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

Dr J R Stockton

unread,
Jun 17, 2010, 6:45:29 PM6/17/10
to
In comp.lang.javascript message <5583d1fb-9746-4999-9d7b-46a0e831bad5@e5
g2000yqn.googlegroups.com>, Wed, 16 Jun 2010 08:30:51, Scott Sauyet
<scott....@gmail.com> posted:

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.

Scott Sauyet

unread,
Jun 19, 2010, 12:01:35 AM6/19/10
to
Dr J R Stockton wrote:
> In comp.lang.javascript message <5583d1fb-9746-4999-9d7b-46a0e831bad5@e5
> g2000yqn.googlegroups.com>, Wed, 16 Jun 2010 08:30:51, Scott Sauyet
> <scott.sau...@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.

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

Ry Nohryb

unread,
Jun 19, 2010, 8:52:41 AM6/19/10
to
On Jun 19, 6:01 am, Scott Sauyet <scott.sau...@gmail.com> wrote:
> (...)

Would you mind to update in your page my code to the latest version ?
It is:

String.prototype.toFP= (function (regExpCache) {
/* 20100531, by jo...@jorgechamorro.com */
return function (base, n, r, w, div) {
if ((base < 2) || (base > 36) || (base % 1)) return NaN;
if (!(n= regExpCache[base])) {
n= "0123456789abcdefghijklmnopqrstuvwxyz".substr(0, base);
n= "^\\s{0,}([-+]{0,1})(["+n+"]{0,})[.]{0,1}(["+n+"]{0,})\
\s{0,}$";
regExpCache[base]= n= new RegExp(n, "i");
}
if (!(n= n.exec(this))) return NaN;
if (isFinite(r= parseInt(n[2] || "0", base)) && (w= n[3].length)) {
while (!isFinite(div= Math.pow(base, w))) w--;
r+= parseInt(n[3].substr(0, w), base)/ div;
}
return (n[1]+ "1")* r;
};
})([]);

TIA,
--
Jorge.

Dr J R Stockton

unread,
Jun 19, 2010, 6:47:16 PM6/19/10
to
In comp.lang.javascript message <4StvyxiT...@invalid.uk.co.demon.me
rlyn.invalid>, Tue, 15 Jun 2010 23:41:23, Dr J R Stockton
<repl...@merlyn.demon.co.uk> posted:

>


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

REPLACE \d with \w. Also, parsFlotC is in hand.

--
(c) John Stockton, nr London UK. ?@merlyn.demon.co.uk Turnpike v6.05 MIME.

Scott Sauyet

unread,
Jun 19, 2010, 9:19:30 PM6/19/10
to
Ry Nohryb wrote:
> On Jun 19, 6:01 am, Scott Sauyet <scott.sau...@gmail.com> wrote:
> Would you mind to update in your page my code to the latest version ?

Not at all. It's in the latest version, here:

<http://scott.sauyet.com/Javascript/Test/2010-06-19a/>

If you have PHP available and want to host your own version, the PHP
is here:

<http://scott.sauyet.com/Javascript/Test/2010-06-19a/index.phps>

--
Scott

Scott Sauyet

unread,
Jun 19, 2010, 9:22:22 PM6/19/10
to
Dr J R Stockton wrote:
> REPLACE \d with \w.  

Done. It's in the latest version, posted here:

<http://scott.sauyet.com/Javascript/Test/2010-06-19a/>

> Also, parsFlotC is in hand.

I look forward to it. I need to find a little time for my next
approach, but I do have a new idea as well.

--
Scott

Dr J R Stockton

unread,
Jun 20, 2010, 1:39:28 PM6/20/10
to
In comp.lang.javascript message <1ba54467-b1ec-423a-9989-4eb3b3288fec@a3
0g2000yqn.googlegroups.com>, Fri, 18 Jun 2010 21:01:35, Scott Sauyet
<scott....@gmail.com> posted:

ExactPF now does not use parseInt. And it has been demoted (in
<URL:http://www.merlyn.demon.co.uk/js-maths.htm#pF>) to be called
BetterPF.

Routines should be tested, base 10, with 0.999999999999999999999999999
for a varying number of nines and similar on other bases. A result of
over 1.0 is bad.

Consider putting the test button somewhere that the
"value" does not cover when showing a list, and putting
the results below, rather than beside, the input.

For production code, ISTM OK to use the default parseFloat for base 10.
On the other hand, that assumes it to be right. But for test ing
conversion code, it is well to have base 10 done in the same way as
other bases, enabling a meaningful comparison with parseFloat.

Function parseFloat should not be used for currency input, since it
inevitably gives inexact Numbers; instead, one should check the format
with a RegExp match and construct the exact number of pennies (does not
apply to much Government work).

Otherwise, the nature of the following calculation is probably such that
an LSB or two of error does not matter; routines such as we have seen
are OK (but one might add handling of exponents such as toString gives).

But, for test purposes, something perfectly accurate at all times is
needed (with rounding into the LSB defined for the half-way case).

--
(c) John Stockton, near London. *@merlyn.demon.co.uk/?.?.Stockton@physics.org


Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.

Correct <= 4-line sig. separator as above, a line precisely "-- " (RFC5536/7)
Do not Mail News to me. Before a reply, quote with ">" or "> " (RFC5536/7)

It is loading more messages.
0 new messages