我总是被告知永远不要代表钱double或float类型,这次我向你提出问题:为什么?
我确信有一个很好的理由,我根本不知道它是什么.
我需要一个简单的浮点舍入函数,因此:
double round(double);
round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1
Run Code Online (Sandbox Code Playgroud)
我能找到ceil()和floor()在math.h中-但不是round().
它是以另一个名称存在于标准C++库中,还是缺少?
我知道0.1十进制数不能用有限的二进制数(解释)精确表示,所以double n = 0.1会失去一些精度而不会完全正确0.1.另一方面0.5可以完全表示,因为它是0.5 = 1/2 = 0.1b.
已经说过,添加0.1 三次不会完全给出0.3以下代码打印是可以理解的false:
double sum = 0, d = 0.1;
for (int i = 0; i < 3; i++)
sum += d;
System.out.println(sum == 0.3); // Prints false, OK
Run Code Online (Sandbox Code Playgroud)
但是,如何增加0.1 五次才会给出确切的答案0.5呢?以下代码打印true:
double sum = 0, d = 0.1;
for (int i = 0; i < 5; i++)
sum += …Run Code Online (Sandbox Code Playgroud) 差异存在于返回值中,我相信这些输入可以打破平局,比如这段代码:
int main()
{
std::cout.precision(100);
double input = std::nextafter(0.05, 0.0) / 0.1;
double x1 = floor(0.5 + input);
double x2 = round(input);
std::cout << x1 << std::endl;
std::cout << x2 << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
哪个输出:
1
0
Run Code Online (Sandbox Code Playgroud)
但它们最终只是不同的结果,人们选择其首选的结果.我看到很多"旧的"C/C++程序floor(0.5 + input)而不是使用round(input).
有历史原因吗?最便宜的CPU?
我经常需要地板或CEIL一CGFloat到int,对于数组索引的计算.
我看到永久的问题floorf(theCGFloat)或者ceilf(theCGFloat)是有可与浮点不准确的麻烦.
那么,如果我CGFloat的2.0f内部被表示为1.999999999999f或类似的东西,那该怎么办呢?我floorf并获得1.0f,这是再次浮动.然而,我必须把这个野兽施放到int,这可能会引入另一个问题.
是否有一个最佳实践如何楼或小区一float到int这样的东西像2.0永远不会意外遭到地板到1让人觉得2.0永远不会意外遭到ceiled来2?
math floating-point floating-accuracy ios floating-point-precision
SO社区是正确的,在你提出性能问题似乎比我随机猜测的方法更有意义之前分析你的代码:-)我描述了我的代码(非常密集的数学)并没有意识到超过70%的代码显然是在一个我没想到的部分是减速,四舍五入的来源.
static double roundTwoDecimals(double d) {
DecimalFormat twoDForm = new DecimalFormat("#.###");
return Double.valueOf(twoDForm.format(d));
}
Run Code Online (Sandbox Code Playgroud)
我的问题是我得到的十进制数通常是.01,.02等.但有时我会得到像.070000000001(我真的只关心0.07,但浮点精度导致我的其他公式导致失败),我只需要前3个小数就可以避免这个问题.
那么有更好/更快的方法吗?
我开发了一个c ++应用程序(Windows 7,64 Bit,VS 2008),其中使用了以下公式(所有变量都是double类型):
mValue = floor(mValue/mStepping)*mStepping;
Run Code Online (Sandbox Code Playgroud)
我们的想法是将数字缩短到给定的小数位数.我认为有更好的方法可以做到这一点,但这不是问题(但如果你有更好的选择,请带上它!).
mValue来自用户输入,因此在大多数情况下,小数位数已经可以.但在某些情况下,输出与输入不同.
例如,mStepping的值为0.1(应该舍入到一个小数位).现在,如果mValue的值为14.6,那么一切正常.如果mValue为14.7,则结果为14.6.
那么,为什么地板(14.7/0.1)*0.1 = 14.6?
我测试了其他值,其中约20%与0.1不同.我进一步挖掘并发现,14.7/0.1具有与147.0不同的二进制编码:
14.7/0.1 = ff ff ff ff ff 5f 62 40
147.0 = 00 00 00 00 00 60 62 40
Run Code Online (Sandbox Code Playgroud)
据我所知,相同的数字可以不同的方式编码为double.但是为什么floor()以不同的方式处理它们?我能做些什么呢?
虽然我已经看到了关于四舍五入的几个问题,但我还没有找到答案.在C#/ .Net中有没有办法进行中点舍入?也就是说,如果小数位于2个整数之间,我想总是向上舍入.据我所知,这是一种常见的舍入方法,所以我很惊讶它没有列在标准的Math.Round选项中.
87.3 -> 87
87.8 -> 88
87.5 -> 88
-87.3 -> -87
-87.8 -> -88
-87.5 -> -87
Run Code Online (Sandbox Code Playgroud)
我能找到的最接近的是MidpointRounding.AwayFromZero,但这会错误地处理负片,因为它们会向下舍入而不是向上.
我在类Math中的静态方法round()中注意到了一个难以理解的事情:
Math.round(0.4999999999999999); // is 0
Math.round(0.49999999999999999); // is 1
Run Code Online (Sandbox Code Playgroud)
为什么?
我想为ex取一个值:
12.166666 ----> 12.00
12.49999 ----> 12.00
12.5111 ----> 13.00
12.9999 ----> 13.00
我想要完成50个paise.