F**p 发帖数: 1046 | 1 我有个程序的浮点运算总是不对:
double x = 0.11985;
double y = 12.5;
double outcome = x * y; //1.4981249570846558
正确答案是1.498125
奇怪之处是我在同一个机器上面,开另外一个visual studio跑一样的code,结果就是
对的。实在搞不懂是为什么。
这里牛人多,求答案!
stackflow上的帖子:
http://stackoverflow.com/questions/21757849/wrong-floating-numb |
v******n 发帖数: 421 | 2 也许是debugger/expression evaluator的问题,你用Console.WriteLine
打印出来看看
【在 F**p 的大作中提到】 : 我有个程序的浮点运算总是不对: : double x = 0.11985; : double y = 12.5; : double outcome = x * y; //1.4981249570846558 : 正确答案是1.498125 : 奇怪之处是我在同一个机器上面,开另外一个visual studio跑一样的code,结果就是 : 对的。实在搞不懂是为什么。 : 这里牛人多,求答案! : stackflow上的帖子: : http://stackoverflow.com/questions/21757849/wrong-floating-numb
|
F**p 发帖数: 1046 | 3 结果肯定是不对的,否则不会发现这个问题。
【在 v******n 的大作中提到】 : 也许是debugger/expression evaluator的问题,你用Console.WriteLine : 打印出来看看
|
d******k 发帖数: 4295 | 4 跟double储存的方式有关,计算时建议用decimal type。
double outcome1 = 12.6*0.11985;
1.5101099999999998
double outcome2 = 12.6d*0.11985d;
1.5101099999999998
double outcome3 = 12.6f*0.11985f;
1.5101100738072404
double outcome4 = (double)(12.6m*0.11985m);
1.51011 |
n***e 发帖数: 723 | 5 是不是。net可以选择build target为any cpu,然后某些情况程序为32位,某些情况下
为64位?
【在 F**p 的大作中提到】 : 我有个程序的浮点运算总是不对: : double x = 0.11985; : double y = 12.5; : double outcome = x * y; //1.4981249570846558 : 正确答案是1.498125 : 奇怪之处是我在同一个机器上面,开另外一个visual studio跑一样的code,结果就是 : 对的。实在搞不懂是为什么。 : 这里牛人多,求答案! : stackflow上的帖子: : http://stackoverflow.com/questions/21757849/wrong-floating-numb
|
F**p 发帖数: 1046 | 6 build target应该和浮点运算没有关系吧。
【在 n***e 的大作中提到】 : 是不是。net可以选择build target为any cpu,然后某些情况程序为32位,某些情况下 : 为64位?
|
d******k 发帖数: 4295 | 7 乘法运算想保持完全精确的话,可以把double转化成biginteger进行计算。
比如12.5*0.11985 变成125*11985=1498125,然后小数点左移6位。
【在 F**p 的大作中提到】 : 我有个程序的浮点运算总是不对: : double x = 0.11985; : double y = 12.5; : double outcome = x * y; //1.4981249570846558 : 正确答案是1.498125 : 奇怪之处是我在同一个机器上面,开另外一个visual studio跑一样的code,结果就是 : 对的。实在搞不懂是为什么。 : 这里牛人多,求答案! : stackflow上的帖子: : http://stackoverflow.com/questions/21757849/wrong-floating-numb
|
F**p 发帖数: 1046 | 8 缺省的存储方式都是double吧。我不加任何的suffix,程序全部用的double。
我直接做数相乘是对的:比如
double outcome4 = 12.6*0.11985; //1.51011
但是,做变量相乘就不对,比如
double x = 12.6;
double y = 0.11985;
double outcome5 = x * y; //1.5101100206375122
【在 d******k 的大作中提到】 : 跟double储存的方式有关,计算时建议用decimal type。 : double outcome1 = 12.6*0.11985; : 1.5101099999999998 : double outcome2 = 12.6d*0.11985d; : 1.5101099999999998 : double outcome3 = 12.6f*0.11985f; : 1.5101100738072404 : double outcome4 = (double)(12.6m*0.11985m); : 1.51011
|
n***e 发帖数: 723 | 9 http://stackoverflow.com/questions/10444350/c-sharp-loss-of-pre
有人遇到和你一样的问题。
【在 F**p 的大作中提到】 : 缺省的存储方式都是double吧。我不加任何的suffix,程序全部用的double。 : 我直接做数相乘是对的:比如 : double outcome4 = 12.6*0.11985; //1.51011 : 但是,做变量相乘就不对,比如 : double x = 12.6; : double y = 0.11985; : double outcome5 = x * y; //1.5101100206375122
|
T********i 发帖数: 2416 | 10 第一个是编译器算出来的。
第二个是runtime。
double的存储和运算精度就这么高。
【在 F**p 的大作中提到】 : 缺省的存储方式都是double吧。我不加任何的suffix,程序全部用的double。 : 我直接做数相乘是对的:比如 : double outcome4 = 12.6*0.11985; //1.51011 : 但是,做变量相乘就不对,比如 : double x = 12.6; : double y = 0.11985; : double outcome5 = x * y; //1.5101100206375122
|
|
|
a9 发帖数: 21638 | 11 double outcome4 = 12.6*0.11985
你这个没带d,所以并不代表是双精度相乘
【在 F**p 的大作中提到】 : 缺省的存储方式都是double吧。我不加任何的suffix,程序全部用的double。 : 我直接做数相乘是对的:比如 : double outcome4 = 12.6*0.11985; //1.51011 : 但是,做变量相乘就不对,比如 : double x = 12.6; : double y = 0.11985; : double outcome5 = x * y; //1.5101100206375122
|
d****i 发帖数: 4809 | 12 有意思,同样的乘法用C的话,得到的结果完全一样:
#include
int main(int argc, char **argv)
{
double outcome4 = 12.6*0.11985;
double x = 12.6;
double y = 0.11985;
double outcome5 = x * y;
printf("outcome4=%10.8fn", outcome4);
printf("outcome5=%10.8fn", outcome5);
}
>outcome4=1.51011000
>outcome5=1.51011000
难道是.net的问题?
【在 F**p 的大作中提到】 : 缺省的存储方式都是double吧。我不加任何的suffix,程序全部用的double。 : 我直接做数相乘是对的:比如 : double outcome4 = 12.6*0.11985; //1.51011 : 但是,做变量相乘就不对,比如 : double x = 12.6; : double y = 0.11985; : double outcome5 = x * y; //1.5101100206375122
|
F**p 发帖数: 1046 | 13 同样的问题:
double v1 = 0.7;
double v2 = 0.025;
double result = v1 / v2;
我跑出来的结果是 28.0 (人家是27.999999999999996)
郁闷啊~
【在 n***e 的大作中提到】 : http://stackoverflow.com/questions/10444350/c-sharp-loss-of-pre : 有人遇到和你一样的问题。
|
d******k 发帖数: 4295 | 14 还是那个答案,用decimal
【在 F**p 的大作中提到】 : 同样的问题: : double v1 = 0.7; : double v2 = 0.025; : double result = v1 / v2; : 我跑出来的结果是 28.0 (人家是27.999999999999996) : 郁闷啊~
|
F**p 发帖数: 1046 | 15 Double应该可以精确到16-17位有效数字,我的结果只有8位。感觉上是我的double都变
成了float的精度。
【在 T********i 的大作中提到】 : 第一个是编译器算出来的。 : 第二个是runtime。 : double的存储和运算精度就这么高。
|
F**p 发帖数: 1046 | 16 这不是dot net的问题,是我程序的问题。因为我另外开一个vs的窗口,结果和你的一
样。
我只是不知道vs里面有什么设置,能影响到缺省的浮点存储/运算方式。
【在 d****i 的大作中提到】 : 有意思,同样的乘法用C的话,得到的结果完全一样: : #include : int main(int argc, char **argv) : { : double outcome4 = 12.6*0.11985; : double x = 12.6; : double y = 0.11985; : double outcome5 = x * y; : printf("outcome4=%10.8fn", outcome4); : printf("outcome5=%10.8fn", outcome5);
|
d******k 发帖数: 4295 | 17 这个不是精度的问题,是.net怎么储存double
A mathematical or comparison operation that uses a floating-point number
might not yield the same result if a decimal number is used, because the
binary floating-point number might not equal the decimal number. A previous
example illustrated this by displaying the result of multiplying .1 by 10
and adding .1 times.
When accuracy in numeric operations with fractional values is important, you
can use the Decimal rather than the Double type. When accuracy in numeric
operations with integral values beyond the range of the Int64 or UInt64
types is important, use the BigInteger type.
using System;
public class Example
{
public static void Main()
{
Double value = .1;
Double result1 = value * 10;
Double result2 = 0;
for (int ctr = 1; ctr <= 10; ctr++)
result2 += value;
Console.WriteLine(".1 * 10: {0:R}", result1);
Console.WriteLine(".1 Added 10 times: {0:R}", result2);
}
}
// The example displays the following output:
// .1 * 10: 1
// .1 Added 10 times: 0.99999999999999989
http://msdn.microsoft.com/en-us/library/system.double.aspx
【在 F**p 的大作中提到】 : Double应该可以精确到16-17位有效数字,我的结果只有8位。感觉上是我的double都变 : 成了float的精度。
|
F**p 发帖数: 1046 | 18 这些都没法解释为什么2段同样的code,同时在一个机子上跑,出不同结果啊。
previous
you
【在 d******k 的大作中提到】 : 这个不是精度的问题,是.net怎么储存double : A mathematical or comparison operation that uses a floating-point number : might not yield the same result if a decimal number is used, because the : binary floating-point number might not equal the decimal number. A previous : example illustrated this by displaying the result of multiplying .1 by 10 : and adding .1 times. : When accuracy in numeric operations with fractional values is important, you : can use the Decimal rather than the Double type. When accuracy in numeric : operations with integral values beyond the range of the Int64 or UInt64 : types is important, use the BigInteger type.
|
d******k 发帖数: 4295 | 19 我在我机子上测试(vs2010 .net 4.0 和2012 。net 4.5)
double x = 0.11985;
double y = 12.6;
double v= x*y; ////都算的不对
double x = 0.11985;
double y = 12.5;
double v= x*y; ////结果都对。
【在 F**p 的大作中提到】 : 这些都没法解释为什么2段同样的code,同时在一个机子上跑,出不同结果啊。 : : previous : you
|
F**p 发帖数: 1046 | 20 你算的 12.6×0.11985 = 1.5101099999999998, 是不是?
而我的结果是: 1.5101100206375122
有效位数只有8位,这是我不明白的地方。
【在 d******k 的大作中提到】 : 我在我机子上测试(vs2010 .net 4.0 和2012 。net 4.5) : double x = 0.11985; : double y = 12.6; : double v= x*y; ////都算的不对 : double x = 0.11985; : double y = 12.5; : double v= x*y; ////结果都对。
|
|
|
d******k 发帖数: 4295 | 21 恩,我的结果是这个。
要不你用BitConverter.GetBytes( double x )在两段程序里都看看具体byte信息一致
不一致。
BitConverter.GetBytes( x);
{byte[0x00000008]}
[0x00000000]: 0x1f
[0x00000001]: 0xf4
[0x00000002]: 0x6c
[0x00000003]: 0x56
[0x00000004]: 0x7d
[0x00000005]: 0xae
[0x00000006]: 0xbe
[0x00000007]: 0x3f
BitConverter.GetBytes( y);
{byte[0x00000008]}
[0x00000000]: 0x33
[0x00000001]: 0x33
[0x00000002]: 0x33
[0x00000003]: 0x33
[0x00000004]: 0x33
[0x00000005]: 0x33
[0x00000006]: 0x29
[0x00000007]: 0x40
【在 F**p 的大作中提到】 : 你算的 12.6×0.11985 = 1.5101099999999998, 是不是? : 而我的结果是: 1.5101100206375122 : 有效位数只有8位,这是我不明白的地方。
|
v******n 发帖数: 421 | 22 不同版本的.net?
【在 F**p 的大作中提到】 : 这些都没法解释为什么2段同样的code,同时在一个机子上跑,出不同结果啊。 : : previous : you
|
n*w 发帖数: 3393 | 23 在linqpad里试了,用outcome.Dump()。结果是1.498125
il是:
IL_0001: ldc.r8 1F F4 6C 56 7D AE BE 3F
IL_000A: stloc.0 // x
IL_000B: ldc.r8 00 00 00 00 00 00 29 40
IL_0014: stloc.1 // y
IL_0015: ldloc.0 // x
IL_0016: ldloc.1 // y
IL_0017: mul
IL_0018: stloc.2 // outcome
IL_0019: ldloc.2 // outcome
IL_001A: call LINQPad.Extensions.Dump |
t****t 发帖数: 6806 | 24 我不懂C#, 不过很显然这是浮点精度不同的结果. 写了个小程序做试验:
#include
double mul(double a, double b); // return a*b, in another compilation unit
int main(int argc, char **argv)
{
printf("12.6 * 0.11985 = %20.18fn", mul(12.6, 0.11985));
printf("float(12.6 * 0.11985) = %20.18fn", (float)mul(12.6, 0.11985));
printf("12.6f * 0.11985 = %20.18fn", mul(12.6f, 0.11985));
printf("float(12.6f * 0.11985) = %20.18fn", (float)mul(12.6f, 0.11985));
printf("12.6 * 0.11985f = %20.18fn", mul(12.6, 0.11985f));
printf("float(12.6 * 0.11985f) = %20.18fn", (float)mul(12.6, 0.11985f));
printf("12.6f * 0.11985f = %20.18fn", mul(12.6f, 0.11985f));
printf("float(12.6f * 0.11985f) = %20.18fn", (float)mul(12.6f, 0.11985f)
);
}
以上, 我组合12.6和0.11985用double和float表示时相乘的结果, 同时把结果也用
double和float表示. 另外我把乘法放到另
一个编译单元以消除编译优化的影响, 并且关闭所有的优化. 结果是这样的:
12.6 * 0.11985 = 1.510109999999999841
float(12.6 * 0.11985) = 1.510110020637512207
12.6f * 0.11985 = 1.510110045719146754
float(12.6f * 0.11985) = 1.510110020637512207
12.6 * 0.11985f = 1.510110028088092804
float(12.6 * 0.11985f) = 1.510110020637512207
12.6f * 0.11985f = 1.510110073807240383
float(12.6f * 0.11985f) = 1.510110020637512207
两个都是double当然是正确的结果. 你的输出是把结果用float表示造成的. 至于怎么
造成这个结果的, 你自己折腾C#吧.
【在 F**p 的大作中提到】 : 你算的 12.6×0.11985 = 1.5101099999999998, 是不是? : 而我的结果是: 1.5101100206375122 : 有效位数只有8位,这是我不明白的地方。
|
F**p 发帖数: 1046 | 25 谢大牛啊,终于能reproduce了。
不过这样的情况,不明白到底什么地方会强制double转换到float呢?VS里面对Build的
config没多少,更没有对浮点运算做设置的地方。还是c#的compiler因为内存的问题,
在某种情况下,自动用float来代表double?
);
【在 t****t 的大作中提到】 : 我不懂C#, 不过很显然这是浮点精度不同的结果. 写了个小程序做试验: : #include : double mul(double a, double b); // return a*b, in another compilation unit : int main(int argc, char **argv) : { : printf("12.6 * 0.11985 = %20.18fn", mul(12.6, 0.11985)); : printf("float(12.6 * 0.11985) = %20.18fn", (float)mul(12.6, 0.11985)); : printf("12.6f * 0.11985 = %20.18fn", mul(12.6f, 0.11985)); : printf("float(12.6f * 0.11985) = %20.18fn", (float)mul(12.6f, 0.11985)); : printf("12.6 * 0.11985f = %20.18fn", mul(12.6, 0.11985f));
|
p*a 发帖数: 592 | 26 我在visualstudio 2013, 2012,2010里测过了,结果都是一样的,程序如下,
class Program
{
static void Main(string[] args)
{
Console.WriteLine("12.6 * 0.11985 tt= {0:F18}", 12.6 * 0.11985);
Console.WriteLine("float(12.6 * 0.11985) t= {0:F18}", (float)(12
.6 * 0.11985));
Console.WriteLine("12.6f * 0.11985 t= {0:F18}", 12.6f * 0.11985);
Console.WriteLine("float(12.6f * 0.11985) = {0:F18}", (float)(
12.6f * 0.11985));
Console.WriteLine("12.6 * 0.11985f t= {0:F18}", 12.6 * 0.11985f);
Console.WriteLine("float(12.6 * 0.11985f) = {0:F18}", (float)(
12.6 * 0.11985f));
Console.WriteLine("12.6f * 0.11985f t= {0:F18}", 12.6f * 0.
11985f);
Console.WriteLine("float(12.6f * 0.11985f) = {0:F18}", (float)(
12.6f * 0.11985f));
Console.ReadLine();
}
}
结果如下,
12.6 * 0.11985 = 1.510110000000000000
float(12.6 * 0.11985) = 1.510110000000000000
12.6f * 0.11985 = 1.510110045719150000
float(12.6f * 0.11985) = 1.510110000000000000
12.6 * 0.11985f = 1.510110028088090000
float(12.6 * 0.11985f) = 1.510110000000000000
12.6f * 0.11985f = 1.510110000000000000
float(12.6f * 0.11985f) = 1.510110000000000000
各种configuration都试过了,什么any cpu,x86, x64, debug , release, .NET 4.5.1
, 4.5, 4.0, 3.5,结果都是一样的。
);
【在 t****t 的大作中提到】 : 我不懂C#, 不过很显然这是浮点精度不同的结果. 写了个小程序做试验: : #include : double mul(double a, double b); // return a*b, in another compilation unit : int main(int argc, char **argv) : { : printf("12.6 * 0.11985 = %20.18fn", mul(12.6, 0.11985)); : printf("float(12.6 * 0.11985) = %20.18fn", (float)mul(12.6, 0.11985)); : printf("12.6f * 0.11985 = %20.18fn", mul(12.6f, 0.11985)); : printf("float(12.6f * 0.11985) = %20.18fn", (float)mul(12.6f, 0.11985)); : printf("12.6 * 0.11985f = %20.18fn", mul(12.6, 0.11985f));
|
n*w 发帖数: 3393 | 27 maybe the second floor is correct. did you try to view the value in quick
view of visual studio?
);
12
11985);
【在 p*a 的大作中提到】 : 我在visualstudio 2013, 2012,2010里测过了,结果都是一样的,程序如下, : class Program : { : static void Main(string[] args) : { : Console.WriteLine("12.6 * 0.11985 tt= {0:F18}", 12.6 * 0.11985); : Console.WriteLine("float(12.6 * 0.11985) t= {0:F18}", (float)(12 : .6 * 0.11985)); : Console.WriteLine("12.6f * 0.11985 t= {0:F18}", 12.6f * 0.11985); : Console.WriteLine("float(12.6f * 0.11985) = {0:F18}", (float)(
|
F**p 发帖数: 1046 | 28 double x1 = 0.11985;
double y1 = 12.6;
double _outcome = (float)(x1 * y1);
和
double _outcome = (float)(0.11985 * 12.6);
的结果是不一样的。
);
12
11985);
【在 p*a 的大作中提到】 : 我在visualstudio 2013, 2012,2010里测过了,结果都是一样的,程序如下, : class Program : { : static void Main(string[] args) : { : Console.WriteLine("12.6 * 0.11985 tt= {0:F18}", 12.6 * 0.11985); : Console.WriteLine("float(12.6 * 0.11985) t= {0:F18}", (float)(12 : .6 * 0.11985)); : Console.WriteLine("12.6f * 0.11985 t= {0:F18}", 12.6f * 0.11985); : Console.WriteLine("float(12.6f * 0.11985) = {0:F18}", (float)(
|
l*******n 发帖数: 373 | 29 想起一个笑话:
A programmer has a problem. Then he says to himself: "That's easy. I'll
just use a floating point number."
Then he has 1.99999999999997 problems. |
n*w 发帖数: 3393 | 30 第二个在编译时就算了。
【在 F**p 的大作中提到】 : double x1 = 0.11985; : double y1 = 12.6; : double _outcome = (float)(x1 * y1); : 和 : double _outcome = (float)(0.11985 * 12.6); : 的结果是不一样的。 : : ); : 12 : 11985);
|