我试图从变量中提取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
答案 0 :(得分:2)
您可以检查浮点类型表示所使用的基数,检查宏常量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 2 ),其中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;
}
答案 1 :(得分:-1)
我认为它已经发生了#34;因为二进制除法不能完全转换为十进制数字&#34;,但 Bob __ 是正确的!问题正在发生,因为长长的变量有点问题&#34;。所以,我只是更改了代码并使用了我提到的函数 ceil 和 round 。这次我测试了代码,所以我希望它能满足你的需求。
PS1:提取功能真的很有必要。
PS2:不要忘记包含 math.h 库。
PS3:抱歉延迟回答。
#include <iostream>
#include <cmath>
#include <math.h>
using namespace std;
int main()
{
int n = 9, m = 450;
long double S;
S = (long double)n/m;
for(int i=1; i<=20; i++){
cout << fmod(round(fmod(S * 10,10)), 10) << " ";
S *= 10;
}
return 0;
}