Redian新闻
>
一个dot net浮点运算的问题
avatar
一个dot net浮点运算的问题# Programming - 葵花宝典
D*3
1
大家好!我的J1豁免已经提交,大使馆应该还没有发出不持异议信,DOS收到fee和材料
。现在问题是准备换lab,但是在同一个学校内。学校是不是要issue一张新的DS2019?
这样的话是不是需要联系大使馆和DOS,说材料有更新,需要把新的DS2019一起wavier
掉? 谢谢
avatar
A*n
2
1、岳母刺字 岳飞十五六岁时,北方的金人南侵,宋朝当权者腐败无能,节节
败退,国家处在生死存亡的关头。岳飞 岳母刺字投军抗辽。不久因父丧,退伍还乡守
孝。 1126年金兵大举入侵中原,岳飞再次投军。临行前,姚太夫人把岳飞叫到跟前,
说:"现在国难当头,你有什么打算?" "到前线杀敌,精忠报国!" 姚太夫人听了儿
子的回答,十分满意,"精忠报国"正是母亲对儿子的希望。她决定把这四个字刺在儿子
的背上,让他永远铭记在心。 岳飞解开上衣,露出瘦瘦的脊背,请母亲下针。 姚太
夫人问:"孩子,针刺是很痛的,你怕吗?" 岳飞说:"母亲,小小钢针算不了什么,
如果连针都怕,怎么去前线打仗!" 姚太夫人先在岳飞背上写了字,然后用绣花针刺了
起来。刺完之后,岳母又涂上醋墨。从此,"精忠报国"四个字就永不褪色地留在了岳飞
的后背上。 母亲的鼓舞激励着岳飞。岳飞投军后,很快因作战勇敢升秉义郎。这时宋
都开封被金军围困,岳飞随副元帅宗泽前去救援,多次打败金军,受到宗泽的赏识,称
赞他"智勇才艺,古良将不能过",后来成为著名的抗金英雄,受历代人民所敬仰。

2、凿壁偷光 匡衡勤奋好学,但家中没有蜡烛照明。邻家有灯烛,但光亮照不到他
家,匡衡就把墙壁凿了一个洞引来邻家的光亮,让光亮照在书上来读。同乡有个大户人
家叫文不识的,是个有钱的人,家中有很多书。匡衡就到他家去做雇工,又不要报酬。
主人感到很奇怪,问他为什么这样,他说:“我希望能得到你家的书,通读一遍。”主
人听了,深为感叹,就把书借给他读。于是匡衡成了大学问家。
avatar
F*p
3
我有个程序的浮点运算总是不对:
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
avatar
s*u
4
No need do anything if DOS did not ask you to do so.
Just wait. If you get FR on 7/1/12, all DS-2019 before that day all get
waiver.
学校是不是要issue一张新的DS2019?No need if in same 学校.

wavier

【在 D*******3 的大作中提到】
: 大家好!我的J1豁免已经提交,大使馆应该还没有发出不持异议信,DOS收到fee和材料
: 。现在问题是准备换lab,但是在同一个学校内。学校是不是要issue一张新的DS2019?
: 这样的话是不是需要联系大使馆和DOS,说材料有更新,需要把新的DS2019一起wavier
: 掉? 谢谢

avatar
v*n
5
也许是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

avatar
D*3
6
非常感谢!!
请问FR是指?

【在 s**u 的大作中提到】
: No need do anything if DOS did not ask you to do so.
: Just wait. If you get FR on 7/1/12, all DS-2019 before that day all get
: waiver.
: 学校是不是要issue一张新的DS2019?No need if in same 学校.
:
: wavier

avatar
F*p
7
结果肯定是不对的,否则不会发现这个问题。

【在 v******n 的大作中提到】
: 也许是debugger/expression evaluator的问题,你用Console.WriteLine
: 打印出来看看

avatar
s*u
8
FR means favorable recommendation letter from DOS.

【在 D*******3 的大作中提到】
: 非常感谢!!
: 请问FR是指?

avatar
d*k
9
跟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
avatar
n*e
10
是不是。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

avatar
F*p
11
build target应该和浮点运算没有关系吧。

【在 n***e 的大作中提到】
: 是不是。net可以选择build target为any cpu,然后某些情况程序为32位,某些情况下
: 为64位?

avatar
d*k
12
乘法运算想保持完全精确的话,可以把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

avatar
F*p
13
缺省的存储方式都是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

avatar
n*e
14
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

avatar
T*i
15
第一个是编译器算出来的。
第二个是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

avatar
a9
16
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

avatar
d*i
17
有意思,同样的乘法用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

avatar
d*k
19
还是那个答案,用decimal

【在 F**p 的大作中提到】
: 同样的问题:
: double v1 = 0.7;
: double v2 = 0.025;
: double result = v1 / v2;
: 我跑出来的结果是 28.0 (人家是27.999999999999996)
: 郁闷啊~

avatar
F*p
20
Double应该可以精确到16-17位有效数字,我的结果只有8位。感觉上是我的double都变
成了float的精度。

【在 T********i 的大作中提到】
: 第一个是编译器算出来的。
: 第二个是runtime。
: double的存储和运算精度就这么高。

avatar
F*p
21
这不是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);

avatar
d*k
22
这个不是精度的问题,是.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的精度。

avatar
F*p
23
这些都没法解释为什么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.

avatar
d*k
24
我在我机子上测试(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

avatar
F*p
25
你算的 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; ////结果都对。

avatar
d*k
26
恩,我的结果是这个。
要不你用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位,这是我不明白的地方。

avatar
v*n
27
不同版本的.net?

【在 F**p 的大作中提到】
: 这些都没法解释为什么2段同样的code,同时在一个机子上跑,出不同结果啊。
:
: previous
: you

avatar
n*w
28
在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
avatar
t*t
29
我不懂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位,这是我不明白的地方。

avatar
F*p
30
谢大牛啊,终于能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));

avatar
p*a
31
我在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));

avatar
n*w
32
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)(

avatar
F*p
33
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)(

avatar
l*n
34
想起一个笑话:
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.
avatar
n*w
35
第二个在编译时就算了。

【在 F**p 的大作中提到】
: double x1 = 0.11985;
: double y1 = 12.6;
: double _outcome = (float)(x1 * y1);
: 和
: double _outcome = (float)(0.11985 * 12.6);
: 的结果是不一样的。
:
: );
: 12
: 11985);

相关阅读
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。