Floating point 舍入问题.Net Core 3.1与.Net Core 2.0/.Net Framework
我在.NET Core 3.0和.NET Framework/.NET Core 2.x之间遇到了一些取整问题 我已经在网上搜索了一段时间,但是我找不到合适的词来搜索,所以我把它贴在这里 我编写了以下示例控制台应用程序来说明我的问题:Floating point 舍入问题.Net Core 3.1与.Net Core 2.0/.Net Framework,floating-point,rounding,precision,.net-framework-version,.net-core-3.1,Floating Point,Rounding,Precision,.net Framework Version,.net Core 3.1,我在.NET Core 3.0和.NET Framework/.NET Core 2.x之间遇到了一些取整问题 我已经在网上搜索了一段时间,但是我找不到合适的词来搜索,所以我把它贴在这里 我编写了以下示例控制台应用程序来说明我的问题: 类程序 { 静态void Main(字符串[]参数) { 常数双x=123.4567890/3.14159265358979; 控制台写入线(x); 常数双y=98.76543210/3.14159265358979; 控制台写入线(y); 常数双z=11.223
类程序
{
静态void Main(字符串[]参数)
{
常数双x=123.4567890/3.14159265358979;
控制台写入线(x);
常数双y=98.76543210/3.14159265358979;
控制台写入线(y);
常数双z=11.2233445566778899/3.14159265358979;
控制台写入线(z);
Console.ReadKey();
}
}
我在不同的框架上运行了这个程序,得到了以下输出:
- .NET Framework 4.7.2
- 392975164552063
- 314380134506439
- 357250152843761
- .NET核心2.0:
- 392975164552063
- 314380134506439
- 357250152843761
- .NET核心3.0:
- 392975164552063
- 31438013450643936
- 35725015284376096
//排列
常数双期望值=0.1232342802302;
//表演
var result=Subject.Calculate();
//断言
结果应为(期望值);
如果我迁移代码并运行测试(我将其写入.NET Framework),测试将失败。我有一些细微的差别,比如
预期项[0]为0.4451391569556069,但找到0.44513915698437145。
预期结果为-13.142181869094,但发现为-13.142181869062。
我的问题是,;我如何强制使用与.NET Framework/.NET Core 2.0相同的方法对.NET Core 3.0进行取整,因此我不会得到这些细微差别
谁能解释一下这种差异/描述一下.NET Core 3.1与.NET Framework的舍入变化?这太奇怪了。。。。我已经设置了一个包含4个项目的解决方案
- NET Framework 4.7.2项目
- NET核心2.0项目
- NET核心3.1项目
- NET Core 3.1项目,一次运行所有3个项目
Math.PI
常量来查看是否有什么变化,事实上确实如此,但不是我所期望的
如果我运行第四个项目,调用所有3个的项目,我会得到这个结果
因此,所有3个项目的值都是相同的。
但如果我单独运行这些,我会得到以下结果:
.NET框架
.NET核心2
.NET核心3
因此,出于某种原因,我在.NET内核中使用Math.PI
常量得到了与您不同的结果,这些结果在版本2和版本3.1之间是相同的。但是,我得到的结果与使用.NET Framework得到的结果相同,这与两个.NET内核不同。但正如我们在上面看到的,如果您从.NETCore中生成的另一个项目运行所有3个项目,您会得到相同的结果,这意味着可能是调用项目决定应该使用什么舍入。不幸的是,我找不到发生这种情况的确切原因,但是如果我没记错的话,在Windows和Unix系统中舍入的工作方式有一些细微的差别。由于.NET Core是跨平台的,我认为它使用的是Unix舍入,而不是.NET Framework可能使用的Windows舍入,这导致了这些差异
编辑:这已经超越了科学的范畴了。。。
我使用了3.14159265358979
的常量值,而不是Math.PI
,这在理论上是相同的(根据)。但使用此值后,结果会再次发生变化!如果在所有3个项目都在运行的地方运行测试,您仍然会得到所有3个项目的相同结果,但这些结果与上一次运行的结果不同
39,2975164552063
31,438013450643936
3,5725015284376096
启动.NET Framework项目时,您会得到与以前相同的结果,而运行.NET核心项目时,您会得到上述结果。因此,使用常量值,而不是Math.PI
,再次更改结果。但这是毫无意义的,因为在引擎盖下,Math.PI
只是一个双常量,值为3.14159265358979
编辑2:我用Python编写了相同的程序
def main():
x = 123.4567890 / 3.14159265358979
print(x)
y = 98.76543210 / 3.14159265358979
print(y)
z = 11.2233445566778899 / 3.14159265358979
print(z)
if __name__ == "__main__":
main()
结果与.NETCore相同
39.2975164552063
31.438013450643936
3.5725015284376096
然后我试着用Go做同样的事情
package main
import "fmt"
func main() {
x := 123.4567890 / 3.14159265358979
fmt.Println(x)
y := 98.76543210 / 3.14159265358979
fmt.Println(y)
z := 11.2233445566778899 / 3.14159265358979
fmt.Println(z)
}
在这种情况下,结果如下
39.2975164552063
31.43801345064394
3.5725015284376096
y
已四舍五入为.94
,而x
和z
与python和.NET核心相同
作为最后一个测试,我尝试使用Javascript/Node.JS来实现这一点
let x = 123.456789 / 3.14159265358979;
console.log(x);
let y = 98.7654321 / 3.14159265358979;
console.log(y);
let z = 11.2233445566778899 / 3.14159265358979;
console.log(z);
但这里的结果也与python和.NETCore相同
39.2975164552063
31.438013450643936
3.5725015284376096
从Python、JS、.NETCARE和GO(如果你不考虑<代码> y>代码>舍入),都是跨平台的,我假设有一些与.NETFramework依赖的Windows生态系统相关的东西。尝试与Windows相关的其他框架/语言会很有趣,但除了.NET Framework(可能是Visual Basic?)之外,我不知道还有其他框架/语言。
这是一个有文档记录的更改,使格式化程序和解析器符合IEEE 754-2008。从.NET 3.0的新增功能文档中的部分:
漂浮
const double y = 98.76543210 / 3.14159265358979;
Console.WriteLine(y);
Console.WriteLine("{0:G15}",y);
31.438013450643936
31.4380134506439