From: glathoud on
Hello,

I've just had the following issue in Safari 5:

0 == (0.17 * 2) >> 0 // -> true
0 == (0.17 * [0,1].length) >> 0 // -> false (!)

and here is a possible workaround:

a = (0.17 * [0,1].length) >> 0
0 == a // -> true

(results are the same with ===)

I hope this helps someone,
Guillaume
From: Dr J R Stockton on
In comp.lang.javascript message <3e7b3e7c-eb62-45b1-ba72-25e4cef86722(a)g1
9g2000yqc.googlegroups.com>, Thu, 15 Jul 2010 00:40:54, glathoud
<glathoud(a)yahoo.fr> posted:

>I've just had the following issue in Safari 5:
>
>0 == (0.17 * 2) >> 0 // -> true
>0 == (0.17 * [0,1].length) >> 0 // -> false (!)
>
>and here is a possible workaround:
>
>a = (0.17 * [0,1].length) >> 0
>0 == a // -> true
>
>(results are the same with ===)
>
>I hope this helps someone,

It would have more chance of doing so if the host system were stated.
Safari seem to be singularly inept at helping users to update in a
timely fashion; as far as I know, my Safari 4.0.5 is the latest Windows
version. Under "Help" it has "Report Bugs to Apple" - were you able to
do that?

I don't see the error in 4.0.5.

--
(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.
From: Swifty on
On Sat, 17 Jul 2010 19:58:52 +0100, Dr J R Stockton
<reply1028(a)merlyn.demon.co.uk> wrote:

>as far as I know, my Safari 4.0.5 is the latest Windows
>version.

I have 5.0 and it must have come via the standard Apple software
automatic updating process, as I did nothing explicit to obtain it.

--
Steve Swift
http://www.swiftys.org.uk/swifty.html
http://www.ringers.org.uk
From: Ry Nohryb on
On Jul 15, 9:40 am, glathoud <glath...(a)yahoo.fr> wrote:
>
> I've just had the following issue in Safari 5:
>
> 0 == (0.17 * 2) >> 0                 // -> true
> 0 == (0.17 * [0,1].length) >> 0   // -> false (!)

navigator.userAgent
--> "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-us)
AppleWebKit/534.3+ (KHTML, like Gecko) Version/5.0 Safari/533.16"

0 == (0.17 * [0,1].length) >> 0
--> true

0 == (0.17 * [0,1].length) >>> 0
--> true

--
Jorge.
From: Richard Cornford on
On Jul 15, 8:40 am, glathoud wrote:
> Hello,
>
> I've just had the following issue in Safari 5:
>
> 0 == (0.17 * 2) >> 0 // -> true
> 0 == (0.17 * [0,1].length) >> 0 // -> false (!)

I can confirm that in Windows Safari 5.0 (7533.16).

> and here is a possible workaround:

But the obvious question is what exactly is it this is supposed to be
working around? Without being sure about what it is that is being
'worked around' there is a risk of introducing another mystical
incantation into javascript development.

> a = (0.17 * [0,1].length) >> 0
> 0 == a // -> true
>
> (results are the same with ===)

That comment implies that the issue is with the comparison operator.
However,

document.write(
'((0.17 * [0,1].length) >> 0) -> '+
((0.17 * [0,1].length) >> 0)
);

- outputs:-

((0.17 * [0,1].length) >> 0) -> 0.3399999141693115

So it is not the comparison that is the issue. The expression is
evaluating to a non-integer value, which it never should because the
right shift bitwise operation should only act on 32 bit integers by
converting its operands into numbers and then 32 bit integers.

The multiplication can be dismissed from consideration by:-

document.write('(Math.PI >> 0) -> '+(Math.PI >> 0));

- outputting:-

(Math.PI >> 0) -> 3.1415920257568373

So the issue is with the right shift operator, and not just with
shifting by zero as:-

document.write('(Math.PI >> 3) -> '+(Math.PI >> 0));

- outputs:-

(Math.PI >> 3) -> 3.141592025756836

(Note that this value is not the same as for >> 0, and that neither
value shown is Math.PI (both operations have had some impact on the
input value))

However, the right shift operator is apparently not totally defective
as:-

document.write(
'(3.141592653589793 >> 0) -> '+
(3.141592653589793 >> 0)
);

- outputs:-

(3.141592653589793 >> 0) -> 3

-and:-

var m = Math.PI;
document.write('(m >> 0) -> '+(m >> 0));

- outputs:-

(m >> 0) -> 3

- which are correct.

On the other hand:-

function u(){return 4.5;}
document.write('(u() >> 1) -> '+(u() >> 1));

- outputs:-

(u() >> 1) -> 4.500000000000002

(Note that 4.5 is a number that IEEE double precision floating point
numbers can represent precisely, so again this shift operation has
modified the number.)

- while:-

function v(){return 4;}
document.write('(v() >> 1) -> '+(v() >> 1));

- outputs:-

(v() >> 1) -> 2

This suggests that where the left hand side operand of the shift
expression results in an integer value the shift operation will work
correctly (other tests reinforce this impression).

However, it turns out that the right hand side operand also has an
impact:-

document.write('(Math.PI >> -0) -> '+(Math.PI >> -0));

- outputs:-

(Math.PI >> -0) -> 3

- which is correct. In javascript it should not be possible to
discriminate between -0 and +0, but here apparently you can. this makes
a possible work around for right shifting by zero to actually right
shift by -0, but that does not help if you wanted to shift by some other
value.


Note that from this point on I am dropping the - document.write - from
the examples to save space. Each of the following tests had the same
form as the previous ones.

This does, however, suggest for a feature test as:-

((Math.PI >> 0) == (Math.PI >> -0))

- should be true in ES3/5 conforming environments but not true in an
environment where (Math.PI >> 0) comes out as 3.1415920257568373.

However, on Windows Safari 5 this came out as true. Which suggest that
in this context the (Math.PI >> 0) expression evaluated to the correct
value. Reversing the expression to:-

(Math.PI >> -0) == (Math.PI >> 0))

- produced the aberrant false in Windows Safari 5, as did:-

((Math.PI >> 0) == (Math.PI >> 0))

So we are looking at a single expression that fails in one context and
succeeds in another. The implication is that it is the expression to the
right of the equality operator that is failing, but it would be a good
idea to confirm that, and to see if the equality operator itself is
involved in this particular quirk. So:-

((Math.PI >> 0) - (Math.PI >> 0)) -> -0.14159202575683727
((Math.PI >> 1) - (Math.PI >> 1)) -> -2.1415920257568364
((Math.PI >> 1) / (Math.PI >> 1)) -> 0.3183099497965817

(Correct evaluation results should be zeros for the subtractions and one
for the division).

Asymmetrical results are found for subtraction and division operations,
and the asymmetry shows that it is the right hand side operand
expression that is failing, while the left hand operand expression is
being correctly evaluated.

This raises the question of what happens with increasing numbers of
expressions, so:-

(((Math.PI >> 0) - (Math.PI >> 0)) / (Math.PI >> 0))

Results in -0.04507015061025516, which is (((3) - (3.1415920257568373))
/ (3.1415920257568373)) and show that the left most expression evaluated
correctly but both of the following expressions failed. Then:-

(((Math.PI >> 0) - (Math.PI >> 0)) - ((Math.PI >> 0) / (Math.PI >> 0)))

Results in -1.096521875146582, which is ((3 - 3.1415920257568373) - (3 /
3.1415920257568373)), so the left most expression is correct, then next
incorrect, the next correct, and the rightmost incorrect.

A pattern may emerge if this was continued, but does not seem worth
pursuing. It is clear that these failures of shift expressions are
sensitive to the context in which the expression appears. However,
notice that:-

(((Math.PI >> 0) - (4.5 >> 0)) / (Math.PI >> 0))

Resutls in -0.27323979918632646 --> (((3.1415920257568373) - (4)) /
(3.1415920257568373)), and:-

(((Math.PI >> 0) - (u() >> 0)) / (Math.PI >> 0))

Results in -0.47746492469487356 --> (((3) - (4.5000000000000036)) /
(3.1415920257568373))

(where - u - is the function that returns 4.5 defined above) - shows the
leftmost (Math.PI >> 0) expression fail in one case and succeed in
another.

Tests on other bitwise operators show precisely the same issue for
unsigned right shift ( >>> ), but no issues with bitwise OR ( | ).

If you wanted a workaround for this particular Safari 5 bug then I would
suggest replacing all occurrences of - >> 0 - (right shift zero bits)
with - | 0 - (bitwise OR with zero), as that would have the same
truncating side effect for a negligible loss of performance in other
browsers, and when shifting by other numbers of bits, because the shift
expression seems to always be successful when applied to integer values,
it should be practical to apply - | 0 - to the left hand side operand
prior to the application of the shift operation. That is (Math.PI >> 1)
becomes ((Math.PI | 0) >> 1). The effect would be less disruptive (less
obfuscating) than introducing new local variables to hold the results of
pre-evaluated expressions.

On the other hand, I would recommend doing nothing at all and letting
Safari 5 suffer for its faults. For one thing, if a web browser wants to
advertise itself as being the fastest browser ever it would be
hypocritical for it (though its bugs) to force developers to use
workarounds that harm the performance of all of its competitors. The
second reason is that if Safari 5 has been allowed out of the door with
this ridiculous context-sensitive f**k up of a simple low-level
operation in place the odds are really good that there are more. These
days it does not seem sensible to start making new concessions for new
web browsers that cannot even conform to the basics of the ten year old
ES 3 standard.

Richard.