```NaN 的两个案例研究```
Two Case Studies of NaN

原始链接: https://sebsite.pw/w/20260709-nan.html

IEEE-754 标准中的“非数值”(NaN)值经常会破坏编程语言设计中的隐含假设,导致违反直觉的行为。由于大多数对象都被期望遵循自反相等性(x == x),开发人员往往会在该假设下优化代码。 Python 就是一个主要例子:虽然 `nan == nan` 的结果为 `False`,但 Python 的列表比较优化依赖于标识检查(`x is y`),这导致 `[nan] == [nan]` 会返回 `True`。这就造成了逐元素比较与列表相等性判断之间的不一致。 Lua 则展现了更为严重的问题。在其数值型 `for` 循环的实现中,NaN 值会扰乱终止逻辑和增量检查,因为底层比较(例如 `limit < init` 或 `0 < step`)在与 NaN 进行运算时总是失败。因此,循环的行为变得不可预测——根据 NaN 出现的位置,循环有时会执行一次,有时则一次也不执行。 这些案例凸显出,当语言设计者未明确考虑 NaN 时,解释器的内部逻辑就会以古怪且未记录的方式暴露出来。归根结底,NaN 的存在导致了标准数学逻辑与编程语言在实际实现及优化细节之间产生了冲突。

Hacker News新帖 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交登录 关于 NaN 的两个案例研究 (sebsite.pw) 3 点,由 ryantsuji 在 1 小时前发布 | 隐藏 | 过往 | 收藏 | 讨论 帮助 考虑申请 YC 2026 年秋季批次!申请截止日期为 7 月 27 日。 准则 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索:
抱歉。
相关文章

原文

IEEE-754 NaN is weird. and because of that, it's often accidentally left unaccounted for. i found two instances of this leaking into programming language design. that is, the semantics of these languages hold implicit assumptions which break with NaN.

case study 1: python

>>> from math import nan
>>> nan == nan
False
>>> [nan] == [nan]
True

as an optimization, when comparing lists for equality, elements are first compared by identity. they're only checked for equality if their identities are unequal.

in general, it's assumed that an object will always compare equal to itself. this is explicitly noted in the python 3 reference manual:

User-defined classes that customize their comparison behavior should follow some consistency rules, if possible:

  • Equality comparison should be reflexive. In other words, identical objects should compare equal:
    x is y implies x == y

this isn't true for NaN. and that's fine, but because the assumption does hold for pretty much everything else, design choices are made which leave NaN unaccounted for (or at least, give NaN very weird behavior).

to be clear, i'm not necessarily saying that python's behavior here is wrong, or that this optimization is bad because NaN behaves weirdly. but i think it's at least worth pointing out.

case study 2: lua

numerical for-loops in lua look like this:

for i = 1, 10 do
    stuff()
end

the way this is supposed to work is that i starts with the initial value (here that's 1), and each iteration it increments by the step (optional third operand; defaults to 1), until the new value is greater than the limit (10), at which point the loop terminates. so this loop iterates 10 times, from 1 to 10 (inclusive).

so what happens when NaN (0/0) is thrown into the mix? here's the behavior in the reference implementation (puc-rio lua):

-- executes once
for i = 0/0, 10 do
    print(i) -- nan
end

-- executes once
for i = 0/0, 0/0 do
    print(i) -- nan
end

-- never executes
for i = 1, 10, 0/0 do
    print(i)
end

-- executes once
for i = 10, 1, 0/0 do
    print(i) -- 10.0
end

read through that code and try to figure out what's going on. every single one of those results is extremely unintuitive.

here's what's happening: the first two only execute once because the for-loop check is implemented as limit < init, but subsequent iterations check idx <= limit. so NaN passes the first test, but not the second test.

the latter two examples show that NaN is always treated as negative when used as the step, even if you do math.abs(0/0). this is because the check for whether the step is positive is 0 < step, which is of course always false for NaN.

none of this is documented btw, so this is likely a genuine oversight. but that's really interesting: using NaN causes the specific comparison operator used by the implementation to leak into the interpreter's behavior.

the simple solution here is to just check for and disallow NaN in numerical for-loops. lua already raises an error when 0 is used as the step, so it's interesting that there's no such check for NaN.

conclusion i guess

Chris Siebenmann also previously wrote about the weird behavior of NaNs as map keys in go, so i guess that makes 3 case studies of NaN's weirdness.

NaN is weird. and that means other things behave weirdly with it.

联系我们 contact @ memedata.com