- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
当我执行这一行时:
double dParsed = double.Parse("0.00000002036");
dParsed实际得到的值:0.000000020360000000000002
相比这条线,
double dInitialized = 0.00000002036;
在这种情况下,dInitialized 的值正好是 0.00000002036
它们在调试器中:
这种不一致有点烦人,因为我想按照以下方式运行测试:
[Subject("parsing doubles")]
public class when_parsing_crazy_doubles
{
static double dInitialized = 0.00000002036;
static double dParsed;
Because of = () => dParsed = double.Parse("0.00000002036");
It should_match = () => dParsed.ShouldBeLike(dInitialized);
}
这当然失败了:
Machine.Specifications.SpecificationException"": Expected: [2.036E-08] But was: [2.036E-08]
在我的生产代码中,“已解析” double 是从数据文件中读取的,而比较值则被硬编码为对象初始值设定项。在数百条记录中,有 4 或 5 条不匹配。原始数据出现在文本文件中是这样的:
0.00000002036 0.90908165072 6256.77753019160
因此被解析的值只有 11 位小数。解决这种不一致的任何想法?
虽然我承认比较 double 是否相等是有风险的,但令我惊讶的是,当文本用作对象初始值设定项时,编译器可以获得准确的表示,但 double.Parse 在解析时无法获得准确的表示完全一样的文字。如何将解析的 double 限制为小数点后 11 位?
最佳答案
Compared to this line,
double dInitialized = 0.00000002036;
in which case the value of dInitialized is exactly 0.00000002036
如果您有任何类似于商用计算机的东西,dInitialized
不会初始化为 0.00000002036。不可能是因为 10 进制数 0.00000002036 在 2 进制中没有有限表示。
您的错误是期望两个 double 比较相等。这通常不是一个好主意。除非你有很好的理由并且知道你在做什么,否则最好不要比较两个 double 是否相等。而是测试两者之间的差异是否在零的某个小 epsilon 范围内。
正确获取 epsilon 的大小有点棘手。如果您的两个数字都很小(例如,小于一个),则 1e-15 的 epsilon 可能很合适。如果数字很大(例如,大于 10),那么小的 epsilon 值相当于测试相等性。
编辑:我没有回答问题。
How can I limit the parsed doubles to 11 decimal places?
如果您不必担心非常小的值,
static double epsilon = 1e-11;
if (Math.Abs(dParsed-dInitialized) > epsilon*Math.Abs(dInitialized)) {
noteTestAsFailed();
}
您应该能够安全地将 epsilon
更改为 4e-16。
编辑 #2: 为什么编译器和 double.Parse
为同一文本生成不同的内部表示?
这很明显,不是吗?编译器和 double.Parse
使用不同的算法。所讨论的数字 0.00000002036 非常接近是否应使用向上舍入或向下舍入来产生在所需值 (0.00000002036) 半个 ULP 范围内的可表示值的风口浪尖。 “正确”值是在所需值的半个 ULP 范围内的值。在这种情况下,编译器做出正确的选择舍入值的决定,而解析器做出错误的选择舍入值的决定。
值 0.00000002036 是一个讨厌的极端情况。它不是一个完全可表示的值。可以精确表示为 IEEE double 的两个最接近的值是 6153432421838462/2^78 和 6153432421838463/2^78。这两者之间的中间值是 12306864843676925/2^79,非常非常接近 0.00000002036。这就是使它成为极端情况的原因。我怀疑您找到的所有编译值与 double.Parse
中的值不完全相同的值都是极端情况,即所需值几乎位于两个最接近的可精确表示值之间的一半的情况。
编辑#3:
这里有许多不同的方式来解释 0.00000002036:
在理想的计算机上,所有这些都是相同的。不要指望在使用有限精度算术的计算机上会出现这种情况。
关于c# - 为什么解析后的 double 不等于假定具有相同值的初始化 double ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21484761/
关于 Stylus 的一大优点是它允许您定义可用于自定义结果输出配置的变量。 例如, // my-html-object.styl $my-html-object-color = red $my-ht
我是 C++ 的新手,只有一个 C++ 的小头文件,里面有一个简单的结构。 PGNFinder.h: #ifndef PGNFINDER_H #define PGNFINDER_H struct Fi
我正在为 Windows 编写一段 C++ 代码,需要查询进程及其每个单独线程的计时。 为了进行必要的系统调用,我需要进程及其每个线程的句柄。我正在使用 getCurrentProcess 和 get
我正在尝试从数据库中检索数据,但将其限制为每个 View 的特定数量的项目。但相反,我得到了上述错误。我创建了以下函数来检索数据: //function to display jobs functio
我有一个用于我的 C++ 应用程序的 settings.ini 文件,但是我的一个用户 Windows\Temp 坏了,导致它对他来说一团糟。所以我打算将它移到他的用户文件夹中。所以我想在全局变量部分
This post says如果您的数据大于 2GB,您需要 64 位系统用于 MongoDB。 在我的本地机器上,运行 32 位 Mac OS X Leopard 的 64 位 Intel C2D,
Thymeleaf tutorial code 这个 SeedStarter 是如何实例化的?请参阅方法主体显示与对象 SeedStarter 的交互。那么它首先是如何实例化的? 由于这个项目是一个教
因此,在这个相当大的源文件中,我有以下部分,假设在函数 foo 中,从 main 调用: FILE *logfile = NULL if (log_engabled) { char fname
出于某种原因,我坚持使用 List 作为集合类型的模型类,我想在客户端使用该模型。然而,GWT 当然无法序列化 java.util.List。但是,此模型中 List 的所有实现都基于 ArrayLi
如何使用 JavaScript 解析此 CSV? 1363085391,42.890000000000,5.432200000000 1363088879,47.570000000000,4.9818
我正在使用名为 paypal_class 的 codeigniter 库。一切都很好,但是在验证 ipn 函数时我得到了这个错误。 使用未定义的常量主机 - 假定为“主机”,这一定是邮件未发送给用户的
这个问题已经有答案了: Forcing GCC to compile .cpp file as C (2 个回答) 已关闭 10 年前。 我有一个 C++ 项目 [IDE = codelite],它尝
这个问题在这里已经有了答案: Sorting a vector of custom objects (14 个答案) 关闭 6 年前。 我创建了一个 vector vector ,我想根据我定义的参
我是一名优秀的程序员,十分优秀!