Visual c++ 添加带有gmp的浮动会给出“正确”的结果
在下面的代码中,我使用mpf_add添加两个浮点值的字符串表示形式。我现在不明白的是为什么2.2+3.2=5.39999999999999999999999999999999。我本以为gmp足够聪明,可以给出5.4 我不明白gmp是如何浮动的 顺便说一句,当我第一次写这篇文章时,我不知道如何插入小数点,因此在结尾插入加减数字Visual c++ 添加带有gmp的浮动会给出“正确”的结果,visual-c++,floating-point,bignum,gmp,Visual C++,Floating Point,Bignum,Gmp,在下面的代码中,我使用mpf_add添加两个浮点值的字符串表示形式。我现在不明白的是为什么2.2+3.2=5.39999999999999999999999999999999。我本以为gmp足够聪明,可以给出5.4 我不明白gmp是如何浮动的 顺便说一句,当我第一次写这篇文章时,我不知道如何插入小数点,因此在结尾插入加减数字 BSTR __stdcall FBIGSUM(BSTR p1, BSTR p2 ) { USES_CONVERSION; F(n1); F(n2); F(
BSTR __stdcall FBIGSUM(BSTR p1, BSTR p2 ) {
USES_CONVERSION;
F(n1);
F(n2);
F(res);
LPSTR sNum1 = W2A( p1 );
LPSTR sNum2 = W2A( p2 );
mpf_set_str( n1, sNum1, 10 );
mpf_set_str( n2, sNum2, 10 );
mpf_add( res, n1, n2 );
char * buff = (char *) _alloca( 1024 );
char expBuffer[ 20 ];
mp_exp_t exp;
mpf_get_str(buff, &exp, 10, 0, res);
char * temp = ltoa( (long) exp, expBuffer, 10 );
if (exp >= 0) {
strcat(buff, "+" );
}
strcat(buff, expBuffer );
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
return bResult;
}
这是因为在二进制环境中使用浮点算法存在固有的错误
有关更多信息,请参阅标准。这是因为在二进制环境中使用浮点运算会产生固有错误 有关更多信息,请参阅标准。什么 如果您使用二进制编码的十进制而不是浮点数,您可能会得到更好的结果,尽管我不能真正指导您使用任何库
如果您使用二进制编码的十进制而不是浮点数,您可能会得到更好的结果,尽管我不能真正指导您使用任何库来实现这一点。我最终自己回答了这个问题。对我来说,解决办法就是用代码来完成我在学校里经常做的事情。该方法的工作原理如下: 取每个数字,确保小数点右侧的位数相同。因此,如果加上2.1和3.457,将第一个“正常化”为2.100。记录小数点右边的位数,在本例中为三位。 现在去掉小数点,用mpz_add加上两个数字,现在是2100和3457。结果是5557。 最后,从右侧重新插入小数点后的三个字符,给出正确答案5.557。 我在下面的VBScript中原型化了解决方案
function fadd( n1, n2 )
dim s1, s2, max, mul, res
normalise3 n1, n2, s1, s2, max
s1 = replace( s1, ".", "" )
s2 = replace( s2, ".", "" )
mul = clng(s1) + clng(s2)
res = left( mul, len(mul) - max ) & "." & mid( mul, len( mul ) - max + 1 )
fadd = res
end function
sub normalise3( byval n1, byval n2, byref s1, byref s2, byref numOfDigits )
dim a1, a2
dim max
if instr( n1, "." ) = 0 then n1 = n1 & "."
if instr( n2, "." ) = 0 then n2 = n2 & "."
a1 = split( n1, "." )
a2 = split( n2, "." )
max = len( a1(1) )
if len( a2(1) ) > max then max = len( a2( 1 ) )
s1 = a1(0) & "." & a1(1) & string( max - len( a1( 1 )), "0" )
s2 = a2(0) & "." & a2(1) & string( max - len( a2( 1 )), "0" )
numOfDigits = max
end sub
最后在Visual C++下面。
#define Z(x) mpz_t x; mpz_init( x );
BSTR __stdcall FADD( BSTR p1, BSTR p2 ) {
USES_CONVERSION;
LPSTR sP1 = W2A( p1 );
LPSTR sP2 = W2A( p2 );
char LeftOf1[ 1024 ];
char RightOf1[ 1024 ];
char LeftOf2[ 1024 ];
char RightOf2[ 1024 ];
char * dotPos;
long numOfDigits;
int i;
int amtOfZeroes;
dotPos = strstr( sP1, "." );
if ( dotPos == NULL ) {
strcpy( LeftOf1, sP1 );
*RightOf1 = '\0';
} else {
*dotPos = '\0';
strcpy( LeftOf1, sP1 );
strcpy( RightOf1, (dotPos + 1) );
}
dotPos = strstr( sP2, "." );
if ( dotPos == NULL ) {
strcpy( LeftOf2, sP2 );
*RightOf2 = '\0';
} else {
*dotPos = '\0';
strcpy( LeftOf2, sP2 );
strcpy( RightOf2, (dotPos + 1) );
}
numOfDigits = strlen( RightOf1 ) > strlen( RightOf2 ) ? strlen( RightOf1 ) : strlen( RightOf2 );
strcpy( sP1, LeftOf1 );
strcat( sP1, RightOf1 );
amtOfZeroes = numOfDigits - strlen( RightOf1 );
for ( i = 0; i < amtOfZeroes; i++ ) {
strcat( sP1, "0" );
}
strcpy( sP2, LeftOf2 );
strcat( sP2, RightOf2 );
amtOfZeroes = numOfDigits - strlen( RightOf2 );
for ( i = 0; i < amtOfZeroes; i++ ) {
strcat( sP2, "0" );
}
Z(n1);
Z(n2);
Z(res);
mpz_set_str( n1, sP1, 10 );
mpz_set_str( n2, sP2, 10 );
mpz_add( res, n1, n2 );
char * buff = (char *) _alloca( mpz_sizeinbase( res, 10 ) + 2 + 1 );
mpz_get_str(buff, 10, res);
char * here = buff + strlen(buff) - numOfDigits;
memmove( here + 1, here, strlen(buff)); // plus trailing null
*(here) = '.';
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
return bResult;
}
我承认C有点。。。好狡猾的,所以请随意批评它。所有有帮助的评论都收到了
我从这里开始实施FSUB和FMUL。FDIV并不是那么令人满意,它有三个版本,并且使用了有理数。我最终自己回答了这个问题。对我来说,解决办法就是用代码来完成我在学校里经常做的事情。该方法的工作原理如下: 取每个数字,确保小数点右侧的位数相同。因此,如果加上2.1和3.457,将第一个“正常化”为2.100。记录小数点右边的位数,在本例中为三位。 现在去掉小数点,用mpz_add加上两个数字,现在是2100和3457。结果是5557。 最后,从右侧重新插入小数点后的三个字符,给出正确答案5.557。 我在下面的VBScript中原型化了解决方案
function fadd( n1, n2 )
dim s1, s2, max, mul, res
normalise3 n1, n2, s1, s2, max
s1 = replace( s1, ".", "" )
s2 = replace( s2, ".", "" )
mul = clng(s1) + clng(s2)
res = left( mul, len(mul) - max ) & "." & mid( mul, len( mul ) - max + 1 )
fadd = res
end function
sub normalise3( byval n1, byval n2, byref s1, byref s2, byref numOfDigits )
dim a1, a2
dim max
if instr( n1, "." ) = 0 then n1 = n1 & "."
if instr( n2, "." ) = 0 then n2 = n2 & "."
a1 = split( n1, "." )
a2 = split( n2, "." )
max = len( a1(1) )
if len( a2(1) ) > max then max = len( a2( 1 ) )
s1 = a1(0) & "." & a1(1) & string( max - len( a1( 1 )), "0" )
s2 = a2(0) & "." & a2(1) & string( max - len( a2( 1 )), "0" )
numOfDigits = max
end sub
最后在Visual C++下面。
#define Z(x) mpz_t x; mpz_init( x );
BSTR __stdcall FADD( BSTR p1, BSTR p2 ) {
USES_CONVERSION;
LPSTR sP1 = W2A( p1 );
LPSTR sP2 = W2A( p2 );
char LeftOf1[ 1024 ];
char RightOf1[ 1024 ];
char LeftOf2[ 1024 ];
char RightOf2[ 1024 ];
char * dotPos;
long numOfDigits;
int i;
int amtOfZeroes;
dotPos = strstr( sP1, "." );
if ( dotPos == NULL ) {
strcpy( LeftOf1, sP1 );
*RightOf1 = '\0';
} else {
*dotPos = '\0';
strcpy( LeftOf1, sP1 );
strcpy( RightOf1, (dotPos + 1) );
}
dotPos = strstr( sP2, "." );
if ( dotPos == NULL ) {
strcpy( LeftOf2, sP2 );
*RightOf2 = '\0';
} else {
*dotPos = '\0';
strcpy( LeftOf2, sP2 );
strcpy( RightOf2, (dotPos + 1) );
}
numOfDigits = strlen( RightOf1 ) > strlen( RightOf2 ) ? strlen( RightOf1 ) : strlen( RightOf2 );
strcpy( sP1, LeftOf1 );
strcat( sP1, RightOf1 );
amtOfZeroes = numOfDigits - strlen( RightOf1 );
for ( i = 0; i < amtOfZeroes; i++ ) {
strcat( sP1, "0" );
}
strcpy( sP2, LeftOf2 );
strcat( sP2, RightOf2 );
amtOfZeroes = numOfDigits - strlen( RightOf2 );
for ( i = 0; i < amtOfZeroes; i++ ) {
strcat( sP2, "0" );
}
Z(n1);
Z(n2);
Z(res);
mpz_set_str( n1, sP1, 10 );
mpz_set_str( n2, sP2, 10 );
mpz_add( res, n1, n2 );
char * buff = (char *) _alloca( mpz_sizeinbase( res, 10 ) + 2 + 1 );
mpz_get_str(buff, 10, res);
char * here = buff + strlen(buff) - numOfDigits;
memmove( here + 1, here, strlen(buff)); // plus trailing null
*(here) = '.';
BSTR bResult = _com_util::ConvertStringToBSTR( buff );
return bResult;
}
我承认C有点。。。好狡猾的,所以请随意批评它。所有有帮助的评论都收到了
我从这里开始实施FSUB和FMUL。FDIV并不是那么令人满意,它有三个版本,并且使用了有理数。最简单的是使用mpq\u t,对有理数的运算是精确的。最简单的是使用mpq\u t,对有理数的运算是精确的。