Math.sign vs ±0
Math.sign
is expected to represent the mathematical sign function, which has a precise definition, see 1, 2. Please note that +0
and -0
are the same value as far as maths is concerned, and that value is neither positive nor negative. (Or both nonnegative and nonpositive, if you prefer.)
More generally, ES treats mathematically equal values as equal for any well-defined mathematical operation: doing otherwise would be new and unexpectedly complex (if you allow me to borrow your words).
Unfortunately Claude, ES Math.sign is not Signum; it has five outputs, not three, like Oliver was asking about. Observe:
> Math.sign(1 / 0)
1
> Math.sign(-1 / 0)
-1
> Math.sign(-1 / 0 * 0)
NaN
> Math.sign(0 * -1)
-0
> Math.sign(0 * 1)
0
Signum as specified in your link produces three outputs: 0, -1, and 1.
Sure, ES Math.sign
cannot be Signum, because real numbers cannot be represented in ES: Numbers in ES are just an approximation of a mathematical concept.
From a mathematical point of view, +0
and -0
is the same thing and NaN
does not exist; so that Math.sign
has really three meaningful outputs when interpreted mathematically: -1, 0, and 1.
In general, I expect that the Math
namespace to hold functions that correspond to definite mathematical operations, and to provide an approximation of those operations, as close as it is reasonable when taking in account the similarities and the differences between numbers in ES and numbers in maths. (From that point of view, I think that Math.imul
and Math.fround
should probably not belong to the Math
namespace... but I digress.)
Claude Pache wrote:
Math.sign
is expected to represent the mathematical sign function, which has a precise definition, see [1], [2]. Please note that+0
and-0
are the same value as far as maths is concerned, and that value is neither positive nor negative. (Or both nonnegative and nonpositive, if you prefer.)
I don't think it's quite that cut and dry. For one thing, the Wolfram resource you linked to states (at the very bottom):
sgn(0) can also be interpreted as an unspecified point on the unit circle in the complex plane (Rich and Jeffrey 1996).
Since ES is (currently) limited to the Real numbers, that would make the only possible choices on the unit circle +1 and -1. It wouldn't be such a leap to choose +1 for +0 and -1 for -0, given that IEEE/ES has both forms of 0.
Furthermore, +0 and -0 can have two different meanings. They're used to represent the mathematical concept of 0 but they're also used to represent +ε and -ε respectively. Since, sgn(+ε) = 1 and sgn(-ε) = -1, I think it would be a valid interpretation mathematically for Math.sign(+0)
to be 1 and Math.sign(-0)
to be -1.
At the very least, I think Oliver has a point in that it'd be very useful to have a sign function which would return 1 for +0 and -1 for -0. I've needed this in the past. If it shouldn't be Math.sign
, perhaps there should be a Number.sign
which would match the other use-case (one that I think would be more useful for meta-programming than what we have for Math.sign
).
Nathan Wall wrote:
At the very least, I think Oliver has a point in that it'd be very useful to have a sign function which would return 1 for +0 and -1 for -0. I've needed this in the past. If it shouldn't be
Math.sign
, perhaps there should be aNumber.sign
which would match the other use-case (one that I think would be more useful for meta-programming than what we have forMath.sign
).
On the other hand, it would probably confuse a lot of novice programmers who aren't familiar with IEEE 754 if sign(0) returned 1. I could see that showing up in a list of JS WTFs. ;)
On Oct 29, 2013, at 8:54 PM, Oliver Hunt wrote:
What is the rational for this behaviour?
Current Math.sign is a new, and unexpectedly complex API that doesn’t solve the common use case.
It's just a matter of IEEE floats and consistency among the ES Math functions
Consistant handling of NaN requires that Math.sign(NaN) produces NaN. So that means there needs to be at least four possible different return values from Math.sign.
The fifth possible returned value derives from the handling of +/- 0. If you look at the other Math function you will see the all of them(except for Math.abs) that map 0 to 0 preserve the sign of the 0 input.
Note that Java uses an identical definition for its signum function: docs.oracle.com/javase/7/docs/api/java/lang/Math.html#signum(float)
Finally, +0 and -0 compare as equal using both == and ===, so the impact of propagating -0 is small in mormal usage.?
On Mon, Nov 4, 2013 at 4:10 AM, Ingvar Stepanyan <me at rreverser.com> wrote:
Why can’t we do Uint64 class inside Math namespace to be used for all the 64-bit arithmetic operations?
Like:
var x = Math.Uint64(2); var y = Math.Uint64.fromString(“0x12345678abcdef01”); var z = x.mul(y); // or Math.Uint64.mul(x, y) var z_hi = z.hi; // highest 32-bit part var z_lo = z.lo; // lowest 32-bit part var z_val = Number(z); // or z.valueOf(), returns IEEE.754-compatible float64 number when possible (with highest possible precision, so no loss up to +-2^52)
Such syntax looks not so “low-level” for JS devs, should be easily polyfilled by current engines and optimized by new ones.
Please read and review the value types proposal strawman:value_types which will eventually replace the current contents of value objects strawman:value_objects
That's strange. I believe I replied to different thread. Sorry.
Sent from my Windows Phone
There's no particular reason not to do something like that, except:
-
It is not usable (see www.jroller.com/cpurdy/entry/the_seven_habits_of_highly1%23comment-1130764636000).
-
Math is becoming a dumping ground, as noted up-thread.
-
Polyfillability is not important if old code can hand-code for better perf, and all evidence is that it can.
Hacking JS into an uglier state for short-term illusory wins, not a good plan!
As currently specified Math.sign has 5 different return values and, as far as i can tell, does not solve the problem I thought it was trying to address. That is the difficulty in distinguishing positive and negative numbers without having to manually do the divide -> ±Infinity cruft.
What is the rational for this behaviour?
Current Math.sign is a new, and unexpectedly complex API that doesn’t solve the common use case.