在以下程序中,您可以看到每个值略小于.5向下舍入,除了0.5.
for (int i = 10; i >= 0; i--) {
long l = Double.doubleToLongBits(i + 0.5);
double x;
do {
x = Double.longBitsToDouble(l);
System.out.println(x + " rounded is " + Math.round(x));
l--;
} while (Math.round(x) > i);
}
Run Code Online (Sandbox Code Playgroud)
版画
10.5 rounded is 11
10.499999999999998 rounded is 10
9.5 rounded is 10
9.499999999999998 rounded is 9
8.5 rounded is 9
8.499999999999998 rounded is 8
7.5 rounded is 8
7.499999999999999 rounded is 7
6.5 rounded is 7 …Run Code Online (Sandbox Code Playgroud) 可能重复:
C++中float的round()
我有一个双(称为x),意味着55,但实际存储为54.999999999999943157,我刚才意识到.
所以,当我这样做
double x = 54.999999999999943157;
int y = (int) x;
Run Code Online (Sandbox Code Playgroud)
y = 54而不是55!
这困惑了我很久了.如何让它正确圆?
差异存在于返回值中,我相信这些输入可以打破平局,比如这段代码:
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?
我想检查boost::variant在我的代码中应用的程序集输出,以便查看哪些中间调用被优化掉了.
当我编译以下示例(使用GCC 5.3 g++ -O3 -std=c++14 -S)时,似乎编译器优化了所有内容并直接返回100:
(...)
main:
.LFB9320:
.cfi_startproc
movl $100, %eax
ret
.cfi_endproc
(...)
Run Code Online (Sandbox Code Playgroud)
#include <boost/variant.hpp>
struct Foo
{
int get() { return 100; }
};
struct Bar
{
int get() { return 999; }
};
using Variant = boost::variant<Foo, Bar>;
int run(Variant v)
{
return boost::apply_visitor([](auto& x){return x.get();}, v);
}
int main()
{
Foo f;
return run(f);
}
Run Code Online (Sandbox Code Playgroud)
但是,完整的程序集输出包含的内容远远超过上面的摘录,对我而言,它看起来永远不会被调用.有没有办法告诉GCC/clang删除所有"噪音"并输出程序运行时实际调用的内容?
完整装配输出:
.file "main1.cpp"
.section .rodata.str1.8,"aMS",@progbits,1
.align 8
.LC0:
.string "/opt/boost/include/boost/variant/detail/forced_return.hpp"
.section .rodata.str1.1,"aMS",@progbits,1
.LC1: …Run Code Online (Sandbox Code Playgroud) 我在 Fortran 和 C++ 中分别实现了一个函数:
#include <math.h>
void dbl_sqrt_c(double *x, double *y){
*y = sqrt(*x - 1.0);
return;
}
Run Code Online (Sandbox Code Playgroud)
pure subroutine my_dbl_sqrt(x,y) bind(c, name="dbl_sqrt_fort")
USE, INTRINSIC :: ISO_C_BINDING
implicit none
real(kind=c_double), intent(in) :: x
real(kind=c_double), intent(out) :: y
y = sqrt(x - 1d0)
end subroutine my_dbl_sqrt
Run Code Online (Sandbox Code Playgroud)
我在编译器资源管理器中比较了它们:
Fortran:https : //godbolt.org/z/froz4rx97
C++:https : //godbolt.org/z/45aex99Yz
我阅读汇编程序的方式,它们基本上做相同的事情,但是 C++ 检查 sqrt 的参数是否为负,而 Fortran 则没有。我使用 googles 基准比较了它们的性能,但它们非常匹配:
--------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------
bm_dbl_c/8 2.07 ns 2.07 ns 335965892
bm_dbl_fort/8 2.06 ns 2.06 …Run Code Online (Sandbox Code Playgroud) 我正在使用VS2008并且我已经包含math.h但我仍然找不到圆函数.它存在吗?
我在google上看到一堆"添加0.5并转换为int"解决方案.这是最好的做法吗?
我最近写了一些代码(ISO/ANSI C),并对它所取得的糟糕表现感到惊讶.长话短说,事实证明罪魁祸首就是这个floor()功能.它不仅速度慢,而且没有矢量化(使用英特尔编译器,也称为ICL).
以下是为2D矩阵中的所有单元格执行底板的一些基准:
VC: 0.10
ICL: 0.20
Run Code Online (Sandbox Code Playgroud)
将其与简单的演员比较:
VC: 0.04
ICL: 0.04
Run Code Online (Sandbox Code Playgroud)
怎么会floor()比简单演员慢得多?!它基本上是相同的(负数除外).第二个问题:有人知道超快的floor()实施吗?
PS:这是我进行基准测试的循环:
void Floor(float *matA, int *intA, const int height, const int width, const int width_aligned)
{
float *rowA=NULL;
int *intRowA=NULL;
int row, col;
for(row=0 ; row<height ; ++row){
rowA = matA + row*width_aligned;
intRowA = intA + row*width_aligned;
#pragma ivdep
for(col=0 ; col<width; ++col){
/*intRowA[col] = floor(rowA[col]);*/
intRowA[col] = (int)(rowA[col]);
}
}
}
Run Code Online (Sandbox Code Playgroud) 例如,这篇博客说0.005并不完全是0.005,但是舍入这个数字会产生正确的结果.
我在C++中尝试了各种舍入,但在将数字舍入到某些小数位时失败了.例如,Round(x,y)将x舍入为y的倍数.所以回合(37.785,0.01)应该给你37.79而不是37.78.
我正在重新打开这个问题,向社区寻求帮助.问题在于浮点数的不精确性(37,785表示为37.78499999999).
问题是Excel如何解决这个问题?
我经常看到代码将int转换为双精度转换为双精度并再次转换(有时候出于好的理由,有时候没有),而且我刚刚想到这似乎是我程序中的"隐藏"成本.我们假设转换方法是截断.
那么,它有多贵?我确定它会因硬件而异,所以让我们假设一个新的英特尔处理器(Haswell,如果你愿意,虽然我会采取任何措施).我会感兴趣的一些指标(虽然一个好的答案不需要全部):
我还假设我们最敏锐地体验慢转换的影响的方式是关于功率使用而不是执行速度,因为我们每秒可以执行多少次计算相对于实际到达的数据量的差异在每秒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