浮点到整数转换出错(即使浮点数已经是整数)
float to int conversion going wrong (even though the float is already an int)
我正在编写一个小函数来使用 c++ 提供的 tgamma 函数来计算二项式系数。 tgamma 返回浮点值,但我想返回一个整数。请看一下这个示例程序,比较三种将浮点数转换回 int 的方法:
#include <iostream>
#include <cmath>
int BinCoeffnear(int n,int k){
return std::nearbyint( std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1)) );
}
int BinCoeffcast(int n,int k){
return static_cast<int>( std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1)) );
}
int BinCoeff(int n,int k){
return (int) std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1));
}
int main()
{
int n = 7;
int k = 2;
std::cout << "Correct: " << std::tgamma(7+1) / (std::tgamma(2+1)*std::tgamma(7-2+1)); //returns 21
std::cout << " BinCoeff: " << BinCoeff(n,k); //returns 20
std::cout << " StaticCast: " << BinCoeffcast(n,k); //returns 20
std::cout << " nearby int: " << BinCoeffnear(n,k); //returns 21
return 0;
}
为什么,即使计算返回等于 21 的浮点数,"正常"转换也会失败,只有 nearint 返回正确的值。实现这一点的最佳方法是什么?
编辑:根据C ++文档,tgamma(int(返回一个双精度值。
从这个std::tgamma
参考:
如果 arg 是自然数,
std::tgamma(arg)
是 arg-1 的阶乘。如果参数是足够小的整数,则许多实现会计算确切的整数域阶乘。
似乎您正在使用的编译器正在这样做,计算表达式std::tgamma(7+1)
的7
阶乘。
结果可能因编译器而异,也可能因优化级别而异。正如 Jonas 所证明的那样,优化和未优化的构建之间存在很大差异。
@nos 的这句话说得很中肯。请注意,第一行
std::cout << "Correct: " <<
std::tgamma(7+1) / (std::tgamma(2+1)*std::tgamma(7-2+1));
打印double
值,但不执行浮点到整数的转换。
浮点计算的结果确实小于 21,但这个double precision
值被cout
打印为 21。
在我的机器上(x86_64,gnu libc,g++ 4.8,优化级别 0(,设置cout.precision(18)
使结果明确。
Correct: 20.9999999999999964 BinCoeff: 20 StaticCast: 20 nearby int: 21
在这种情况下,用浮点运算替换整数运算是可行的,但必须记住结果必须是整数。目的是使用std::round
.
std::nearbyint
的问题在于,根据舍入模式的不同,它可能会产生不同的结果。
std::fesetround(FE_DOWNWARD);
std::cout << " nearby int: " << BinCoeffnear(n,k);
将返回 20。
因此,std::round
BinCoeff 函数可能看起来像
int BinCoeffRound(int n,int k){
return static_cast<int>(
std::round(
std::tgamma(n+1) /
(std::tgamma(k+1)*std::tgamma(n-k+1))
));
}
浮点数具有与之关联的舍入错误。这里有一篇关于这个主题的好文章:每个计算机科学家都应该知道的关于浮点运算的知识。
在您的情况下,浮点数的值非常接近但小于21
。隐式浮积分转换的规则说:
数部分被截断,即小数部分是 丢弃。
而std::nearbyint
:
使用当前舍入模式将浮点参数 arg 舍入为浮点格式的整数值。
在这种情况下,浮点数将正好21
,以下隐式转换将返回21
。
前cout
输出21
,因为默认情况下在cout
中发生舍入。请参阅std::setprecition
。
这是一个活生生的例子。
实现这一点的最佳方法是什么?
使用获取并返回unsigned int
而不是tgamma
的精确整数阶乘函数。
问题在于处理floats
。 花车不能2
像2
那样,而是1.99999
类似的东西。 因此,转换为 int 将删除小数部分。
因此,与其立即转换为 int,不如通过调用在cmath
或math.h
中声明的ceil
函数 w/c 来将其转换为 int。
此代码将返回所有 21
个#include <iostream>
#include <cmath>
int BinCoeffnear(int n,int k){
return std::nearbyint( std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1)) );
}
int BinCoeffcast(int n,int k){
return static_cast<int>( ceil(std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1))) );
}
int BinCoeff(int n,int k){
return (int) ceil(std::tgamma(n+1) / (std::tgamma(k+1)*std::tgamma(n-k+1)));
}
int main()
{
int n = 7;
int k = 2;
std::cout << "Correct: " << (std::tgamma(7+1) / (std::tgamma(2+1)*std::tgamma(7-2+1))); //returns 21
std::cout << " BinCoeff: " << BinCoeff(n,k); //returns 20
std::cout << " StaticCast: " << BinCoeffcast(n,k); //returns 20
std::cout << " nearby int: " << BinCoeffnear(n,k); //returns 21
std::cout << "n" << (int)(2.9995) << "n";
}
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 将字符串转换为浮点数或整数,而无需使用内置函数(如 atoi 或 atof)
- 为什么将两个浮点数相加会得到一个整数C++?
- 浮点数中整数的精确表示形式
- 浮点到整数转换出错(即使浮点数已经是整数)
- 将整数的二进制数据转换为浮点数
- 当我们C++将两个数组的整数除以 时,如何获得浮点数计算;
- C++整数除法到浮点数
- 整数浮点数除以自身是否保证为 1.f?
- 如何使用 c++ 模板实现整数、字符串、浮点数和日期对象的数组
- 根据浮点数选择最小整数类型
- 如何将 Q 格式的整数转换为浮点数(反之亦然)
- 解析文本文件中的字符串、整数和浮点数
- 正则表达式浮点数和不带逗号的整数
- 如何在不使用对象的情况下连接字符串、整数和浮点数
- 将 32 位浮点数和不强制转换的 32 位整数与双精度进行比较,当其中一个值可能太大而无法完全适合另一种类型时
- 整数/浮点数/字符串值之间的操作,组合太多
- 为什么整数/浮点数乘法会导致不同的结果
- 如何使用zmq/zeromq从传递给python的字符串表示(字节数组)中获取整数/浮点数