C# 中的双精度数、整数、Math.Round
我必须将双精度值 x 转换为以下指定的两个整数...
“x 字段由两个带符号的 32 位整数组成:x_i 表示整数部分,x_f 表示小数部分乘以 10^8。例如: x of 80.99 的 x_i 为 80,x_f 为 99,000,000"
首先我尝试了以下方法,但有时似乎会失败,给出 xF 值1999999 当它应该是 2000000
// Doesn't work, sometimes we get 1999999 in the xF
int xI = (int)x;
int xF = (int)(((x - (double)xI) * 100000000));
以下似乎适用于我测试过的所有情况。但我想知道是否有更好的方法可以在不进行循环调用的情况下做到这一点。而且,是否存在仍然会失败的情况?
// Works, we get 2000000 but there's the round call
int xI = (int)x;
double temp = Math.Round(x - (double)xI, 6);
int xF = (int)(temp * 100000000);
I have to convert a double value x into two integers as specified by the following...
"x field consists of two signed 32 bit integers: x_i which represents the integral part and x_f which represents the fractional part multiplied by 10^8. e.g.: x of 80.99 will have x_i as 80 and x_f as 99,000,000"
First I tried the following, but it seems to fail sometimes, giving an xF value of 1999999 when it ought to be 2000000
// Doesn't work, sometimes we get 1999999 in the xF
int xI = (int)x;
int xF = (int)(((x - (double)xI) * 100000000));
The following seems to work in all the cases that I've tested. But I was wondering if there's a better way to do it without the round call. And also, could there be cases where this could still fail?
// Works, we get 2000000 but there's the round call
int xI = (int)x;
double temp = Math.Round(x - (double)xI, 6);
int xF = (int)(temp * 100000000);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
问题是 (1) 二进制浮点以精度换取范围,以及 (2) 某些值(例如 3.1)无法以标准二进制浮点格式(例如 IEEE 754-2008)精确表示。
首先阅读 David Goldberg 的 “What Every”计算机科学家应该了解浮点算术”,发表于 ACM 计算调查,第 23 卷,第 1 期,3 月1991。
然后请参阅这些页面,了解有关使用浮点数存储精确值的危险、陷阱和陷阱的更多信息:
http://steve.hollasch.net/cgindex/coding/ieeefloat.html
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
当 System.Decimal 为您提供精确的十进制浮点数时,为什么要自己动手呢?
但是,如果你打算这样做,像这样的事情应该可以满足你的要求:
The problem is (1) that binary floating point trades precision for range and (2) certain values, such as 3.1 cannot be repsented exactly in standard binary floating point formats, such as IEEE 754-2008.
First read David Goldberg's "What Every Computer Scientist Should Know About Floating-Point Arithmetic", published in ACM Computing Surveys, Vol 23, No 1, March 1991.
Then see these pages for more on the dangers, pitfalls and traps of using floats to store exact values:
http://steve.hollasch.net/cgindex/coding/ieeefloat.html
http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
Why roll your own when System.Decimal gives you precise decimal floating point?
But, if your going to do it, something like this should do you just fine:
我认为使用小数可以解决问题,因为在内部它们实际上使用数字的十进制表示形式。使用 double 将数字的二进制表示形式转换为十进制时会出现舍入错误。试试这个:
编辑:与 RuneFS 的无休止的讨论表明事情并不那么容易。因此,我做了一个非常简单的测试,迭代次数为一百万次:
在这个测试中,51.6% 的仅双精度转换失败,而当数字首先转换为十进制时,没有转换失败。
I think using decimals solve the problem, because internally they really use a decimal representation of the numbers. With double you get rounding errors when converting the binary representation of a number to decimal. Try this:
EDIT: The endless discussion with RuneFS shows that the matter is not that easy. Therefore I made a very simple test with one million iterations:
In this Test 51.6% of the doubles-only conversion fail, where as no conversion fails when the number is converted to decimal first.
有两个问题:
您的输入值很少会等于小数点后 8 位的十进制表示形式。因此某种舍入是不可避免的。换句话说:您的数字
i.20000000
实际上会略小于或略大于i.2
。转换为
int
总是向零舍入。这就是为什么,如果i.20000000
小于i.2
,您将得到小数部分的19999999
。使用Convert.ToInt32
四舍五入到最接近的值,这正是您想要的。在所有情况下,它都会为您提供20000000
。因此,只要您的所有数字都在
0
-99999999.99999999
范围内,以下内容将始终为您提供最接近的解决方案:当然,正如其他人所建议的那样,转换为
十进制
并使用它进行计算是一个很好的选择。There are two issues:
Your input value will rarely be equal to its decimal representation with 8 digits after the decimal point. So some kind of rounding is inevitable. In other words: your number
i.20000000
will actually be slightly less or slightly more thani.2
.Casting to
int
always rounds towards zero. This is why, ifi.20000000
is less thani.2
, you will get19999999
for the fractional part. UsingConvert.ToInt32
rounds to nearest, which is what you'll want here. It will give you20000000
in all cases.So, provided all your numbers are in the range
0
-99999999.99999999
, the following will always get you the nearest solution:Of course, as others have suggested, converting to
decimal
and using that for your calculations is an excellent option.