我可以使用什么算法将十进制数转换并输入到c ++中的分数形式。例如,如果我输入1.25,我希望转换为输出为1 1/4。
答案 0 :(得分:6)
首先得到小数部分,然后取gcd。使用欧几里德算法http://en.wikipedia.org/wiki/Euclidean_algorithm
void foo(double input)
{
double integral = std::floor(input);
double frac = input - integral;
const long precision = 1000000000; // This is the accuracy.
long gcd_ = gcd(round(frac * precision), precision);
long denominator = precision / gcd_;
long numerator = round(frac * precision) / gcd_;
std::cout << integral << " + ";
std::cout << numerator << " / " << denominator << std::endl;
}
long gcd(long a, long b)
{
if (a == 0)
return b;
else if (b == 0)
return a;
if (a < b)
return gcd(a, b % a);
else
return gcd(b, a % b);
}
答案 1 :(得分:4)
#include <iostream>
#include <valarray>
using namespace std;
void as_fraction(double number, int cycles = 10, double precision = 5e-4){
int sign = number > 0 ? 1 : -1;
number = number * sign; //abs(number);
double new_number,whole_part;
double decimal_part = number - (int)number;
int counter = 0;
valarray<double> vec_1{double((int) number), 1}, vec_2{1,0}, temporary;
while(decimal_part > precision & counter < cycles){
new_number = 1 / decimal_part;
whole_part = (int) new_number;
temporary = vec_1;
vec_1 = whole_part * vec_1 + vec_2;
vec_2 = temporary;
decimal_part = new_number - whole_part;
counter += 1;
}
cout<<"x: "<< number <<"\tFraction: " << sign * vec_1[0]<<'/'<< vec_1[1]<<endl;
}
int main()
{
as_fraction(3.142857);
as_fraction(0.1);
as_fraction(0.333333);
as_fraction(514.0/37.0);
as_fraction(1.17171717);
as_fraction(-1.17);
}
x: 3.14286 Fraction: 22/7
x: 0.1 Fraction: 1/10
x: 0.333333 Fraction: 1/3
x: 13.8919 Fraction: 514/37
x: 1.17172 Fraction: 116/99
x: 1.17 Fraction: -117/100
有时候,您可能希望近似十进制数而不需要等价。例如,pi = 3.14159近似为22/7或355/113。我们可以使用cycles参数获取这些信息:
as_fraction(3.14159, 1);
as_fraction(3.14159, 2);
as_fraction(3.14159, 3);
x: 3.14159 Fraction: 22/7
x: 3.14159 Fraction: 333/106
x: 3.14159 Fraction: 355/113
答案 2 :(得分:0)
我想出了一个针对这个问题的算法,但我觉得它太冗长了,可以用更少的代码行完成。对于糟糕的缩进感到抱歉很难在溢出时对齐所有内容。
#include <iostream>
using namespace std;
// converts the string half of the inputed decimal number into numerical values void converting
(string decimalNumber, float&numerator, float& denominator )
{ float number; string valueAfterPoint =decimalNumber.substr(decimalNumber.find("." ((decimalNumber.length() -1) )); // store the value after the decimal into a valueAfterPoint
int length = valueAfterPoint.length(); //stores the length of the value after the decimal point into length
numerator = atof(valueAfterPoint.c_str()); // converts the string type decimal number into a float value and stores it into the numerator
// loop increases the decimal value of the numerator by multiples of ten as long as the length is above zero of the decimal
for (; length > 0; length--)
numerator *= 10;
do
denominator *=10;
while (denominator < numerator);
// simplifies the the converted values of the numerator and denominator into simpler values for an easier to read output
void simplifying (float& numerator, float& denominator) { int maximumNumber = 9; //Numbers in the tenths place can only range from zero to nine so the maximum number for a position in a position for the decimal number will be nine
bool isDivisble; // is used as a checker to verify whether the value of the numerator has the found the dividing number that will a value of zero
// Will check to see if the numerator divided denominator is will equal to zero
if(int(numerator) % int(denominator) == 0) {
numerator /= denominator;
denominator = 1;
return; }
//check to see if the maximum number is greater than the denominator to simplify to lowest form while (maximumNumber < denominator) { maximumNumber *=10; }
// the maximum number loops from nine to zero. This conditions stops if the function isDivisible is true
for(; maximumNumber > 0;maximumNumber --){
isDivisble = ((int(numerator) % maximumNumber == 0) && int(denominator)% maximumNumber == 0);
if(isDivisble)
{
numerator /= maximumNumber; // when is divisible true numerator be devided by the max number value for example 25/5 = numerator = 5
denominator /= maximumNumber; //// when is divisible true denominator be devided by themax number value for example 100/5 = denominator = 20
}
// stop value if numerator and denominator is lower than 17 than it is at the lowest value
int stop = numerator + denominator;
if (stop < 17)
{
return;
} } }
答案 3 :(得分:0)
(评论太久了。)
一些评论声称这是不可能的。但是我有相反的意见。
我认为正确的解释是可能的,但很容易错误地陈述问题或误解答案。
这里提出的问题是找到给定浮点值的有理逼近。
这肯定是可能的,因为C ++中使用的浮点格式只能存储有理值,通常以符号/尾数/指数的形式存储。以IEEE-754单精度格式为例(为了简化数字),0.333
是stored as 1499698695241728 * 2^(-52)
。这等于其convergents提供increasingly accurate approximations的分数1499698695241728 / 2^52
一直到原始值:1/3
,333/1000
,77590/233003
,5586813/16777216
。
这里有两点需要注意。
对于变量float x = 0.333;
来说,最佳有理逼近不一定是333 / 1000
,因为存储的值并非完全准确,而是{{ 1}},因为浮点数内部表示的精度有限。
一旦分配了浮点值,就不会存储浮点值或源代码是否将其定义为0.333
和0.333000004291534423828125
,因为这两个值都具有{ {3}}内部表示。这就是为什么无法解决(将相关的但不同的)数字的字符串表示形式分为整数部分和小数部分的问题(相关但不同),方法是先转换为浮点,然后在转换后的值。
[ EDIT ]}以下是float x = 0.333;
示例的分步详细信息。
float x = 0.333000004;
转换为精确分数的代码。0.333f
float
这将#include <cfloat>
#include <cmath>
#include <limits>
#include <iostream>
#include <iomanip>
void flo2frac(float val, unsigned long long* num, unsigned long long* den, int* pwr)
{
float mul = std::powf(FLT_RADIX, FLT_MANT_DIG);
*den = (unsigned long long)mul;
*num = (unsigned long long)(std::frexp(val, pwr) * mul);
pwr -= FLT_MANT_DIG;
}
void cout_flo2frac(float val)
{
unsigned long long num, den; int pwr;
flo2frac(val, &num, &den, &pwr);
std::cout.precision(std::numeric_limits<float>::max_digits10);
std::cout << val << " = " << num << " / " << den << " * " << FLT_RADIX << "^(" << pwr << ")" << std::endl;
}
int main()
{
cout_flo2frac(0.333f);
}
合理地表示为0.333000004 = 11173626 / 16777216 * 2^(-1)
。
剩下要做的是确定精确分数的收敛,这只能使用整数计算来完成。 Output是(由WA提供):
float val = 0.333f;