最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Pure function given strictly equal arguments yielding non-strictly equal results - Stack Overflow

programmeradmin2浏览0评论

Below is a pure function f for which f(a) !== f(b) despite a === b (notice the strict equalities) for some values of a and b:

var f = function (x) {
   return 1 / x;
}

+0 === -0 // true
f(+0) === f(-0) // false

The existence of such functions can lead to difficult-to-find bugs. Are there other examples I should be weary of?

Below is a pure function f for which f(a) !== f(b) despite a === b (notice the strict equalities) for some values of a and b:

var f = function (x) {
   return 1 / x;
}

+0 === -0 // true
f(+0) === f(-0) // false

The existence of such functions can lead to difficult-to-find bugs. Are there other examples I should be weary of?

Share Improve this question edited Nov 17, 2012 at 7:57 Randomblue asked Aug 28, 2011 at 19:58 RandomblueRandomblue 116k150 gold badges362 silver badges556 bronze badges 6
  • 1 Is this a programming problem? I'm not sure I quite understand the question. – Gabe Commented Aug 28, 2011 at 20:14
  • @Gabe: Well strict equality ===, as the name suggests, should be strict. The function I have provided shows that strict equality is actually not so strict, which is indeed a problem for me. – Randomblue Commented Aug 28, 2011 at 20:16
  • @Random: Strictly equality only means that no type conversion will be performed. -0 and +0 are both numbers. Why would you ever want to distinguish between them anyway? Division by zero is not defined anyway, other languages throw an error in this case. – Felix Kling Commented Aug 28, 2011 at 21:22
  • 1 Because the property a === b implies f(a) === f(b) for pure functions f is a nice one to have, don't you think so? – Randomblue Commented Aug 28, 2011 at 21:25
  • In general maybe. But in JavaScript, if you define +0 !== -0, then this implies that Math.round(-5 / 10) !== 0. And this is probably a much more common situation and and would create much more problems. You also have to consider the practical aspects, not only the theoretical ones. – Felix Kling Commented Aug 28, 2011 at 21:30
 |  Show 1 more comment

6 Answers 6

Reset to default 12

Yes, because NaN !== NaN.

var f = function (x) { return Infinity - x; }

Infinity === Infinity // true
f(Infinity) === f(Infinity) // false

f(Infinity) // NaN

Some other examples that yield NaN whose arguments can be strictly equal:

0/0
Infinity/Infinity
Infinity*0
Math.sqrt(-1)
Math.log(-1)
Math.asin(-2)

this behaviour is perfectly ok, because, in mathematical theory, -0 === +0 is true, and 1/(-0) === 1/(+0) is not, because -inf != +inf

EDIT: although I am really surprised that javascript can in fact handle these kinds of mathematical concepts.

EDIT2: additionally, the phenomenon you described is completely based on the fact, that you divide by zero from which you should expect at least some strange behaviour.

1/+0 is Infinity and 1/-0 -Infinity, while +0 === -0.

This can be explained by the fact that ECMA defines -0 to equal +0 as a special case, while in other operations these two values retain their different properties, which result in some inconsistencies.

This is only possible because the language explicitly defines two non-equal values to be equal, that in fact are not.

Other examples, if any, should be based on the same sort of artificial equality, and given http://ecma262-5.com/ELS5_HTML.htm#Section_11.9.6 there is no other such excention, so probably no other example of this.

If it's of any use, we can ensure that 0 is not -0 by adding 0 to it:

var f = function(x) {
   return 1 / (x + 0);
}
f(+0) === f(-0)

In ECMAScript 3, another example where === behaves surprisingly is with joined functions. Consider a case like this:

function createConstantFunction(result) {
    return function () {
        return result;
    };
}

var oneReturner = createConstantFunction(1);  // a function that always returns 1
var twoReturner = createConstantFunction(2);  // a function that always returns 2

An implementation is allowed to "join" the two functions (see §13.2 of the spec), and if it does so, then oneReturner === twoReturner will be true (see §13.1.2), even though the two functions do different things. Similarly with these:

// a perfect forwarder: returns a sort of "duplicate" of its argument
function duplicateFunction(f) {
    return function (f) {
        return f.apply(this, arguments);
    };
}

var myAlert = duplicateFunction(alert);
console.myLog = duplicateFunction(console.log);

Here an implementation can say that myAlert === console.myLog, even though myAlert is actually equivalent to alert and console.myLog is actually equivalent to console.log.

(However, this aspect of ECMAScript 3 was not preserved in ECMAScript 5: functions are no longer allowed to be joined.)

I'm not so sure this is so scary ;-) Javascript is not a pure language and the presence of +/-0 and the equality of -0 and +0 are specific to IEEE-754 and are "well defined", even if perhaps sometimes surprising. (Even NaN != NaN always being true is well defined, for instance.)

From signed zero:

According to the IEEE 754 standard, negative zero and positive zero should compare as equal with the usual (numerical) comparison operators...

Technically, because the two inputs to f are different, then the result can also be different. For what it's worth, Haskell will treat 0 == -0 as true but will treat (1 / 0) == (1 / (-0)) as false.

However, I do find this an interesting question.

Happy coding.

There are many such functions, here is another example

function f (a) {
  return a + 1;
}

1 == "1" but f(1) != f("1")

This is because equality is a nuanced concept.

Perhaps more scary is that in your example -0 === +0.

发布评论

评论列表(0)

  1. 暂无评论