gpt4 book ai didi

C++除小数错误

转载 作者:行者123 更新时间:2023-11-28 04:59:48 25 4
gpt4 key购买 nike

我试图从一个变量中提取 20 位小数,但除法运算应该有错误,因为这个程序给了我一个错误的结果:

#include <iostream>
#include <cmath>
using namespace std;
int fracpart(long double input)
{
long long I;
I = input * 10;
return I % 10;
}

int main()
{
int n = 9, m = 450;
long double S;
S = (long double)n/m;
for(int i=1; i<=20; i++){
cout << fracpart(S) << " ";
S *= 10;
}
return 0;
}

我得到的:

0 1 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9

我应该得到什么:

0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 

最佳答案

您可以通过检查宏常量 FLT_RADIX 的值来检查浮点类型表示所使用的基数(在 header 中定义 <cfloat> )。您可能已经知道,大多数现代计算机在内部使用二进制系统,而不是十进制系统。

现在考虑一个像 1/3 这样的有理数。它不能用基数为 10 的有限位数表示,您最终会得到一些近似值,例如 0.3333333 和一个可接受的错误。请注意,相同的数字可以在具有有限位数 (0.1) 的 3 进制系统中表示。

您尝试打印的数字 9/450 具有“不错”的以 10 为基数的表示形式 0.02,但它不能以绝对精度以 2 为基数表示,即使可以在不添加任何内容的情况下执行除法错误。不要被“2”误导,考虑 0.02 = 2/100 = 1/50 = 1/(2 * 52),其中 1/5 只能近似计算,在基数2.

无论如何,有一些方法可以实现您想要的,例如使用输出操纵器 std::setprecisionstd::fixed (在 header <iomanip> 中定义)甚至编写一个(非常丑陋的)自定义函数。看看这个程序的输出:

#include <iostream>
#include <cmath>
#include <iomanip>
#include <vector>
#include <cstdint>

// splits a number into its integral and fractional (a vector of digits) parts
std::vector<uint8_t> to_digits (
long double x, uint8_t precision, long double &integral
);

// Reconstructs the approximated number
long double from_digits (
long double integral_part, std::vector<uint8_t> &fractional_part
);

int main()
{
using std::cout;

int n = 9, m = 450;
long double S;
S = static_cast<long double>(n)/m;

cout << "\nBase 10 representation of calculated value:\n"
<< std::setprecision(70) << S << '\n';
// This ^^^^^^^^^^^^^^^^^^^^^ will change only how the value is
// printed, not its internal binary representation

cout << "\nBase 10 representation of literal:\n"
<< 0.02L << '\n';
// This ^^^^^ will print the exact same digits

// the next greater representable value is a worse approximation
cout << "\nNext representable value:\n"
<< std::nextafter(S, 1.0) << '\n';

// but you can try to obtain a "better" output
cout << "\nRounded representation printed using <iomanip> functions:\n"
<< std::setprecision(20) << std::fixed << S << '\n';

cout << "\nRounded fractional part printed using custom function:\n";
long double integral_part;
auto dd = to_digits(S, 20, integral_part);
for (auto const d : dd)
{
cout << static_cast<int>(d);
}
cout << '\n';

// Reversing the process...
cout << "\nApproximated value (using custom function):\n";
auto X = from_digits(integral_part, dd);
cout << std::setprecision(70) << std::fixed << X << '\n';
cout << std::setprecision(20) << std::fixed << X << '\n';
}

std::vector<uint8_t> to_digits (
long double x, uint8_t precision, long double &integral
)
{
std::vector<uint8_t> digits;

long double fractional = std::modf(x, &integral);

for ( uint8_t i = 0; i < precision; ++i )
{
long double digit;
fractional = std::modf(fractional * 10, &digit);
digits.push_back(digit);
}

if ( digits.size() && std::round(fractional) == 1.0L )
{
uint8_t i = digits.size();
while ( i )
{
--i;
if ( digits[i] < 9 )
{
++digits[i];
break;
}
digits[i] = 0;
if ( i == 0 )
{
integral += 1.0L;
break;
}
}
}

return digits;
}

long double from_digits (
long double integral_part, std::vector<uint8_t> &fractional_part
)
{
long double x = 1.0L;
for ( auto d : fractional_part )
{
x *= 10.0L;
integral_part += d / x;
}

return integral_part;
}

关于C++除小数错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46348802/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com