双打的准确性令人沮丧 [英] Accuracy of doubles frustrating

查看:70
本文介绍了双打的准确性令人沮丧的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你会认为在数据类型中额外小数位的优势是

更准确。好好想想。看看这个方法和测试

结果:


====================== ============================ =========

//不只是为了舍入小数,但是为了得到最近的

//整数值。 IE浏览器。最近的(443,5)= 445

公共静态双最近(双源,双最近)

{

//方法1 - 用途模数运算符

//(除法的余数)

double rem = source%nearest;

double dest = source - rem;


//方法2 - 得到没有模数的余数

双倍=来源/最近;

int iTimes =(int)SM.Round (次,0);

// double times2 =(double)iTimes;

double dest2 = iTimes * nearest;


//看看Tostring和back是否有帮助?

string sDest2 = dest2.ToString();

double dest2fs = double.Parse(sDest2);


返回dest2;

}

======================= =========================== =========

测试134.111和.1(完全兼顾两种方式):


来源134.111双

最接近0.1双

rem 0.010999999999982552 double

dest 134.1 double

次1341.11双

iTimes 1341 int

dest2 134.1双

sDest2" 134.1" string

dest2fs 134.1 double


测试55.35和.1(双向错误):


source 55.35双

最近0.1双

rem 0.049999999999998351双

dest 55.300000000000004双

乘553.5双

iTimes 554 int

dest2 55.400000000000006 double

sDest2" 55.4"字符串

dest2fs 55.4双倍

测试35.5和.1(第二路工作,第一路缺陷):


来源35.5双

最近0.1双

rem 0.099999999999998035双

dest 35.4双

乘355.0双< br $>
iTimes 355 int

dest2 35.5 double

sDest2" 35.5" string

dest2fs 35.5 double


我能理解丢失十进制精度,双值接近

double.MaxValue,因为它减少了内存为小数位,但

对于小于100的数字和只有2位小数,为什么会有一个

问题???


我觉得非常奇怪的是test2中的dest2有15个小数位,

但是ToString()方法在第一个零之后切掉所有东西。或者

它可能只是在toString之前四舍五入到最接近的14?在这种情况下,
的方式会是相同的结果。


或者我的处理器有什么问题(移动奔腾4,
$来自康柏的b $ b 3.02ghtz)?您(任何人)可以在您的

机器上验证我的结果吗?如果结果相同,有人可以解释吗?


Michael Lang

You''d think that the advantage to extra decimal places in a data type is
better accuracy. Well think again. Look at this method and test
results:

================================================== =========
// not just for rounding decimals, but for getting nearest
// whole number values. IE. Nearest(443, 5) = 445
public static double Nearest(double source, double nearest)
{
//method 1 - uses modulus operator
// (remainder from division)
double rem = source % nearest;
double dest = source - rem;

//method 2 - get remainder without modulus
double times = source / nearest;
int iTimes = (int)SM.Round(times,0);
//double times2 = (double)iTimes;
double dest2 = iTimes * nearest;

//see if Tostring and back helps?
string sDest2 = dest2.ToString();
double dest2fs = double.Parse(sDest2);

return dest2;
}
================================================== =========

test with 134.111 and .1 (works perfectly both ways):

source 134.111 double
nearest 0.1 double
rem 0.010999999999982552 double
dest 134.1 double
times 1341.11 double
iTimes 1341 int
dest2 134.1 double
sDest2 "134.1" string
dest2fs 134.1 double

test with 55.35 and .1 (round errors both ways):

source 55.35 double
nearest 0.1 double
rem 0.049999999999998351 double
dest 55.300000000000004 double
times 553.5 double
iTimes 554 int
dest2 55.400000000000006 double
sDest2 "55.4" string
dest2fs 55.4 double

test with 35.5 and .1 (works 2nd way, flaw 1st way):

source 35.5 double
nearest 0.1 double
rem 0.099999999999998035 double
dest 35.4 double
times 355.0 double
iTimes 355 int
dest2 35.5 double
sDest2 "35.5" string
dest2fs 35.5 double

I could understand losing decimal accuracy with double values nearing the
double.MaxValue as that leaves less memory for the decimal places, but
for numbers less than 100 and only 2 decimal places, why is there a
problem???

What I find very strange is that dest2 in test2 has 15 decimal places,
but the ToString() method chops off everything after the first zero. Or
it could just be rounding to the nearest 14 before the toString? either
way would be the same result in this case.

Or is there just something wrong with my processor (mobile pentium 4,
3.02ghtz from Compaq)? Can you (anyone) verify my results on your
machine? If same results, can anyone explain?

Michael Lang

推荐答案

Michael Lang< ml @ nospam .COM>写在

新闻:Xn ******************************** @ 207.46.248。 16:
Michael Lang <ml@nospam.com> wrote in
news:Xn********************************@207.46.248 .16:
======================================== ========== =========
//不仅用于舍入小数,而且用于获得最接近的
//整数值。 IE浏览器。最近的(443,5)= 445
公共静态双最近(双源,双最近)
{方法1 - 使用模数运算符
//(来自除法的余数) )
double rem = source%nearest;
double dest = source - rem;

//方法2 - 得到没有模数的余数
double times = source / nearest ;
int iTimes =(int)SM.Round(次,0);
// double times2 =(double)iTimes;
double dest2 = iTimes * nearest;

//看看Tostring和back是否有帮助?
字符串sDest2 = dest2.ToString();
double dest2fs = double.Parse(sDest2);

返回dest2;
}
========================================= ========= =========
================================================== =========
// not just for rounding decimals, but for getting nearest
// whole number values. IE. Nearest(443, 5) = 445
public static double Nearest(double source, double nearest)
{
//method 1 - uses modulus operator
// (remainder from division)
double rem = source % nearest;
double dest = source - rem;

//method 2 - get remainder without modulus
double times = source / nearest;
int iTimes = (int)SM.Round(times,0);
//double times2 = (double)iTimes;
double dest2 = iTimes * nearest;

//see if Tostring and back helps?
string sDest2 = dest2.ToString();
double dest2fs = double.Parse(sDest2);

return dest2;
}
================================================== =========




顺便提一下,一个逻辑变化(以前的结果没有变化):


======================================= ==

//方法1

double rem = source%nearest;

d ouble dest;

if(rem> = nearest / 2)

{

dest = source - rem + nearest;

}

其他

{

dest = source - rem;

}

=========================================


另一个毁灭性的测试结果:


最近呼叫(134.1,.2)。应该得到134.2,但得到:


来源134.1双

最接近0.2双

rem 0.099999999999986877 double

dest 134.0双

次670.49999999999989双

iTimes 670 int

dest2 134.0双

sDest2" 134"字符串

dest2fs 134.0双

134.1 / .2应该等于670.5,它会向上舍入,但因为它只是

下670.5,它向下舍入!


Michael Lang



By the way, one logical change (no change in previous results):

=========================================
//method 1
double rem = source % nearest;
double dest;
if (rem >= nearest/2)
{
dest = source - rem + nearest;
}
else
{
dest = source - rem;
}
=========================================

Another devastating test result:

Call Nearest(134.1, .2). should get "134.2", but get:

source 134.1 double
nearest 0.2 double
rem 0.099999999999986877 double
dest 134.0 double
times 670.49999999999989 double
iTimes 670 int
dest2 134.0 double
sDest2 "134" string
dest2fs 134.0 double

134.1 / .2 should equal 670.5 which would round up, but since it is just
under 670.5, it rounds down!

Michael Lang


嗨迈克尔,


我们在languages.vb小组中查询了为什么5.1 * 100的所有内容都不准确。我会用我给b $ b给出的答复。


< quote>

5.1 * 100很明显510给我们因为我们用十进制的思考。


然后将5.1转换为二进制浮点数,并在''二进制点'之后转换数字

'继续比可用的几个字节长一点。

因此< storage>的事实5.1将引入一个错误 - 更不用说

乘以它。


你会认为它不需要很多位来存储5.1鉴于51

只需要6个!


51 = 32 + 16 + 2 + 1 = 110011


但5.1比这更复杂,因为它是从分数两个b
的两个幂构建的:


5.1 = 4 + 1 + 1/16 + 1 / 32 + 1/256 + 1/512 + 1/2048 + ...


= 11.00011001101000 ...


我们有在''二进制点'之后已经达到了14位数并且它仍然没有

准确,仅为5.09999765625。


有些数字只是穿上不喜欢被转换为两个权力的总和。

< / quote>


现在,如果你认为你的函数中有两个数字,其中一个或两个都可能遭受固有的损失

的准确性 - 从单词go开始。结果可能是复合错误。


您可能不知道的另一个因素是.NET中的舍入是最接近的偶数。一旦

时间1.5,2.5,3.5,4.5,5.5,6.5将转为2,3,4,5,6,7。不再 - 它们如此圆:2,2, 4,4,6,6 !!

的想法是,通过交替四舍五入然后向下,整体的准确性更高。不幸的是,在b / b
重型计算中可能会如此,但在日常编程中这是意外行为 - 即。一个等待被发现的bug。


问候,

Fergus

Hi Michael,

We had a query in the languages.vb group about why 5.1 * 100 of all things wasn''t accurate. I''ll use the reply that I
gave then.

<quote>
5.1 * 100 is so obviously 510 to us because we think in decimal.

Convert 5.1 to a binary floating point number, however, and the digits
after the ''binary point'' go on somewhat longer than the few bytes available.
Thus the very fact of <storing> 5.1 is going to introduce an error - let alone
multiplying it.

You''d think that it wouldn''t need many bits to store 5.1 given that 51
only needs 6!

51 = 32 + 16 + 2 + 1 = 110011

But 5.1 is more complicated than this as it is built up from fractional
powers of two:

5.1 = 4 + 1 + 1/16 + 1/32 + 1/256 + 1/512 + 1/2048 + ...

= 11.00011001101000 ...

We''ve already got to 14 digits after the ''binary point'' and it''s still not
accurate, being only 5.09999765625.

Some numbers just don''t like being converted to sums of powers of two.
</quote>

Now if you consider that you have two numbers in your function, either or both may be suffering from that inherent loss
of accuracy - right from the word go. The result can be a compounded error.

Another factor that you may not be aware of is that rounding in .NET is done to the nearest even number. Once upon a
time 1.5, 2.5, 3.5, 4.5, 5.5, 6.5 would round to 2, 3, 4, 5. 6, 7. Not anymore - they round like so: 2, 2, 4, 4, 6, 6!! The
idea is that by alternately rounding up and then down, the accuracy is greater overall. Unfortunately that may be so in
heavy-duty calculations but in day-to-day programming that is unexpected behaviour - ie. a bug waiting to be discovered.

Regards,
Fergus


Ferg :


我错过了那篇文章,但我刚刚完成了它。非常有启发性!

" Fergus Cooney" <音响**** @ post.com>在消息中写道

news:u
Ferg:

I missed that post, but I just walked through it. Very enlightening!
"Fergus Cooney" <fi****@post.com> wrote in message
news:u


这篇关于双打的准确性令人沮丧的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆