浮点到整数的转换出错(即使浮点已经是整数) 我用C++提供的TGAMM函数编写了一个计算二项式系数的函数。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; } #包括 #包括 int BinCoeffnear(int n,int k){ 返回std::nearbyint(std::tgama(n+1)/(std::tgama(k+1)*std::tgama(n-k+1)); } int BinCoeffcast(int n,int k){ 返回静态(std::tgamma(n+1)/(std::tgamma(k+1)*std::tgamma(n-k+1)); } int BinCoeff(int n,int k){ 返回(int)std::tgama(n+1)/(std::tgama(k+1)*std::tgama(n-k+1)); } int main() { int n=7; int k=2; std::cout

浮点到整数的转换出错(即使浮点已经是整数) 我用C++提供的TGAMM函数编写了一个计算二项式系数的函数。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; } #包括 #包括 int BinCoeffnear(int n,int k){ 返回std::nearbyint(std::tgama(n+1)/(std::tgama(k+1)*std::tgama(n-k+1)); } int BinCoeffcast(int n,int k){ 返回静态(std::tgamma(n+1)/(std::tgamma(k+1)*std::tgamma(n-k+1)); } int BinCoeff(int n,int k){ 返回(int)std::tgama(n+1)/(std::tgama(k+1)*std::tgama(n-k+1)); } int main() { int n=7; int k=2; std::cout,c++,c++11,C++,C++11,浮点数有与其相关的舍入错误。下面是一篇关于这个主题的好文章: 在您的情况下,浮点数的值非常接近,但小于21。例如: 小数部分被截断,即小数部分被截断 丢弃 鉴于: 使用当前舍入模式,将浮点参数arg舍入为浮点格式的整数值 在这种情况下,浮点数正好是21,下面的隐式转换将返回21 第一个cout输出21,因为默认情况下在cout中进行舍入。请参阅 这是一个例子 实现这一点的最佳方式是什么? 使用精确的整数阶乘函数,该函数接受并返回无符号int,而不是tgamma注释@nos是正确的。请注意,第一

浮点数有与其相关的舍入错误。下面是一篇关于这个主题的好文章:

在您的情况下,浮点数的值非常接近,但小于
21
。例如:

小数部分被截断,即小数部分被截断 丢弃

鉴于:

使用当前舍入模式,将浮点参数arg舍入为浮点格式的整数值

在这种情况下,浮点数正好是
21
,下面的隐式转换将返回
21

第一个
cout
输出
21
,因为默认情况下在
cout
中进行舍入。请参阅

这是一个例子


实现这一点的最佳方式是什么?


使用精确的整数阶乘函数,该函数接受并返回
无符号int
,而不是
tgamma

注释@nos是正确的。请注意,第一行

std::cout << "Correct: " << 
 std::tgamma(7+1) / (std::tgamma(2+1)*std::tgamma(7-2+1));
在这种情况下,用浮点运算代替整数运算是可行的,但必须记住结果必须是整数。目的是使用
std::round

std::nearbyint的问题在于,根据取整模式,它可能会产生不同的结果

std::fesetround(FE_DOWNWARD);
std::cout << " nearby int: " << BinCoeffnear(n,k); 

问题在于如何处理
浮动
。 浮动不能
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";
}
#包括
#包括
int BinCoeffnear(int n,int k){
返回std::nearbyint(std::tgama(n+1)/(std::tgama(k+1)*std::tgama(n-k+1));
}
int BinCoeffcast(int n,int k){
返回静态(ceil(标准:tgamma(n+1)/(标准:tgamma(k+1)*标准:tgamma(n-k+1)));
}
int BinCoeff(int n,int k){
返回(int)ceil(std::tgamma(n+1)/(std::tgamma(k+1)*std::tgamma(n-k+1));
}
int main()
{
int n=7;
int k=2;
标准::cout来自:

如果arg是一个自然数,
std::tgamma(arg)
是arg-1的阶乘。如果参数是一个足够小的整数,许多实现都会计算精确的整数域阶乘

您使用的编译器似乎正在这样做,为表达式
std::tgamma(7+1)
计算
7
的阶乘


编译器之间以及优化级别之间的结果可能不同。正如Jonas所证明的,和构建之间存在很大的差异。

可能结果类似于
20.99999
或类似的结果?然后强制转换将截断结果。请记住,计算机上的浮点算法容易出现舍入错误。相关阅读:为了帮助您找出问题所在,可以将表达式拆分为更小的部分,然后将每个较小的部分拆分为更小的部分,依此类推。然后将每个结果分配给一个临时变量。这样,您就可以轻松地逐行遍历代码以查看每一步的结果。请注意,
BinCoeff
确实如此仅对std::tgamma(n+1)
进行强制转换(隐式转换适用于结果),无需将示例与静态_强制转换和C-cast混合。@the.polo,“即使计算返回的浮点值等于21”不完全正确。如果您删除强制转换和int转换并将浮点打印到屏幕上,您可能会被默认精度
std::cout
所愚弄,并且打印浮点值
20.999999999975
的操作将按其显示格式进行四舍五入。在打印浮点值之前,请运行
std::cout.precision(17);
(另请参见@Jonas Ah yes.。这并不能回答为什么
main
中的第一行打印21(没有nearbyint),而第二行打印的是20。那么,实现二项系数的正确方法是什么呢?只需使用
nearbyint
?@the.polo更新了帖子。我认为你应该使用
std::round
,因为
std::nearbyint
会产生不同的结果,这取决于当前的舍入模式。请看一看有关stor的信息用双倍运算整数值。也许需要注意优化水平的依赖性。不过这很好!难道不是“不这样做”意味着不计算精确的整数值吗?显然OP的
std::tgamma(7+1)
并没有产生
21.0
@AMA
std::tgamma(7+1)
要么产生
5040
(优化的构建,等于7!),或者类似于
5039.999999999999999090530
(对于未优化的构建)。正是这种计算上的差异导致了OP的问题。@Someprogrammerdude-oups,是的。我的意思是它正在生成
5039.999999999990905
,因此没有进行优化。
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)) 
                                  ));
}
#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";
}