<form>
<input type="number" step="1" required>
<input type="submit">
</form>Run Code Online (Sandbox Code Playgroud)
在上面的代码段中,如果您插入
0.0000001
Run Code Online (Sandbox Code Playgroud)
输入数字后,您将无法提交表单:“ step”属性可以防止这种情况。
但是如果你插入
0.00000001
Run Code Online (Sandbox Code Playgroud)
它可以在Chrome / Chromium中使用!为什么在验证输入时似乎只读取前七个小数位?是否在任何地方对此进行了记录,并且我可以采取什么措施防止这种情况发生?
我测试了Firefox,它不接受任何此类值。它不能是浮点精度问题(例如0.1 + 0.2),仅与更多的十进制数字有关
0.30000000000000004 === 0.1+0.2
Run Code Online (Sandbox Code Playgroud)
虽然这肯定是您拥有的数字的错误,但它实际上可以防止其他步骤/值集出现问题。分数舍入存在核心问题,使得完美的步骤验证并不那么容易,至少在这种精度水平下是如此。事实上,如果你查看 Firefox 源代码,你可以找到这个评论https://dxr.mozilla.org/mozilla-central/source/dom/html/HTMLInputElement.cpp#4654:
处理小数时可能会出现下面的舍入问题,但在 ECMAScript 为我们提供十进制数字类型之前,我们先忽略它。
所以问题不仅仅存在于 Chrome 上。但让我们从您描述的错误开始。如果你查看 Chromium 源代码,你可以看到在 step_range 处理中,有一个名为AcceptableError的方法,它调整该值与针对步长调整的值之间的差异。请参阅https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/forms/step_range.cc?l=60。这个可接受的误差定义为:
the step value / 2^24 (in the source code UINT64_C(1) << FLT_MANT_DIG)
Run Code Online (Sandbox Code Playgroud)
步长为 1:
1 / 16777216 = 0.000000059604645
Run Code Online (Sandbox Code Playgroud)
因此,在您的原始示例中,任何具有低于该值的余数的数字都将有效,即使它不应该有效。计算余数的公式为:
value - step * Math.abs(Math.round(value / step));
Run Code Online (Sandbox Code Playgroud)
例如,如果您输入 2.000000059604644,则余数将为:
2.000000059604644 - 1 * Math.abs(Math.round(2.000000059604644))
= 2.000000059604644 - 2
= 0.000000059604644
Run Code Online (Sandbox Code Playgroud)
0.000000059604644 低于 0.000000059604645,因此它会验证。2.000000059604646 不会。
the step value / 2^24 (in the source code UINT64_C(1) << FLT_MANT_DIG)
Run Code Online (Sandbox Code Playgroud)
您可以尝试使用更大的数字,例如采用 167772167 的步长。这给出了可接受的错误:
16777217 / 16777216 = 1.000000059604645
Run Code Online (Sandbox Code Playgroud)
对于值为 16777218 的余数:
16777218 - 16777217 * Math.abs(Math.round(1.000000059604645 ))
= 16777218 - 16777217
= 1
Run Code Online (Sandbox Code Playgroud)
1 / 16777216 = 0.000000059604645
Run Code Online (Sandbox Code Playgroud)
这是您可接受的误差 1 以下,因此它会验证。
所以这就是错误。作为报复,它允许容忍某些步骤和值,因为小数运算中精度的损失在它们应该验证时无法验证。在 Firefox 等浏览器中,这正是发生的情况。某些值/步骤对在应该验证时却没有验证。
以步长 853.2394 和值 495714162280.48785 为例。这当然应该得到验证,因为:
495714162280.48785 / 853.2394 = 580978987
Run Code Online (Sandbox Code Playgroud)
如果您在 Firefox 中尝试,它不会验证。但在 Chrome 中,它是有效的,因为容忍导致第一种情况的错误。
value - step * Math.abs(Math.round(value / step));
Run Code Online (Sandbox Code Playgroud)
所以最后,这个错误与小数运算的已知问题有关,这些问题并不精确。典型的例子是 0.1 + 0.2 = 0.30000000000000004。后台发生的事情稍微复杂一点,也更精确一些,但是处理十进制计算的问题导致了这些问题,并且使得它们很难在每种情况下预防。
| 归档时间: |
|
| 查看次数: |
104 次 |
| 最近记录: |