可以检查通过浮点类型检查宏恒定FLT_RADIX
的值的表示所用的碱(在报头<cfloat>
定义)。正如你可能已经知道的那样,二进制系统被大多数现代计算机内部使用,而不是十进制。
现在考虑一个像1/3的有理数。它不能用基数为10的有限数字表示,最终会出现一些近似值,如0.3333333和可接受的错误。请注意,相同的数字可以用有限数量的数字(0.1)在基本3系统中表示。
您尝试打印的数字9/450具有“好”的基数10表示,0.02,但它不能以绝对精度表示在基数2中,即使可以在不添加分割的情况下执行分割任何错误。不要误以为'2',考虑0.02 = 2/100 = 1/50 = 1 /(2 * 5 ),其中1/5只能近似于基数2.
无论如何,有办法实现你想要的,例如使用输出操纵器std::setprecision
和std::fixed
(在标头<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;
}
这看起来像它可能的副本[?是浮点运算破(https://stackoverflow.com/questions/588004/is-floating-point尽管我承认我并不完全确定代码中发生了什么事情。 – Carcigenicate
我试图让一个程序从两个数字的分割中得到20位小数。 –