C++ 如何从一个分数中得到分子和分母?
如何从一个分数中得到分子和分母?例如,从“1.375”中,我希望得到“1375/1000”或“11/8”。我怎么用C++做?C++ 如何从一个分数中得到分子和分母?,c++,C++,如何从一个分数中得到分子和分母?例如,从“1.375”中,我希望得到“1375/1000”或“11/8”。我怎么用C++做? 我试着将点之前和点之后的数字分开,但它没有给出如何获得所需输出的任何想法 > C++中,可以使用Boost Rational类。但你需要给出分子和分母 为此,您需要找出输入字符串中小数点后的数字。您可以通过字符串操纵函数来实现这一点。逐个字符读取输入的字符,并在后找不到任何字符 char inputstr[30]; int noint=0, nodec=0; char
我试着将点之前和点之后的数字分开,但它没有给出如何获得所需输出的任何想法 > C++中,可以使用Boost Rational类。但你需要给出分子和分母 为此,您需要找出输入字符串中小数点后的数字。您可以通过字符串操纵函数来实现这一点。逐个字符读取输入的字符,并在
后找不到任何字符
char inputstr[30];
int noint=0, nodec=0;
char intstr[30], dec[30];
int decimalfound = 0;
int denominator = 1;
int numerator;
scanf("%s",inputstr);
len = strlen(inputstr);
for (int i=0; i<len; i++)
{
if (decimalfound ==0)
{
if (inputstr[i] == '.')
{
decimalfound = 1;
}
else
{
intstr[noint++] = inputstr[i];
}
}
else
{
dec[nodec++] = inputstr[i];
denominator *=10;
}
}
dec[nodec] = '\0';
intstr[noint] = '\0';
numerator = atoi(dec) + (atoi(intstr) * 1000);
// You can now use the numerator and denominator as the fraction,
// either in the Rational class or you can find gcd and divide by
// gcd.
charinputstr[30];
int noint=0,nodec=0;
char intstr[30],dec[30];
整数分频=0;
int分母=1;
整数分子;
scanf(“%s”,inputstr);
len=strlen(inputstr);
对于(int i=0;i我希望我能原谅我发布了一个“只使用C
语言”的答案。我知道你用C++
标记了这个问题-但是我不能拒绝这个诱饵,对不起。这至少仍然是有效的C++
(当然,它主要使用C字符串处理技术)
输出:
30047/2000
完整示例见
注意事项:
int rc = num_string_float_to_rat("0015.0235", &num, &den);
// Check return code -> should be 0!
printf("%ld/%ld\n", num, den);
strtok()
用于将输入解析为令牌(无需在这方面重新发明轮子)。strtok()
修改其输入-因此使用临时缓冲区以确保安全
- 它检查无效字符-如果找到,将返回非零返回码
- 使用了
strtol()
而不是atoi()
——因为它可以检测输入中的非数字字符
scanf()
未被用于含糊输入-由于浮点数的舍入问题
strtol()
的基数已明确设置为10
,以避免前导零出现问题(否则前导零将导致数字被解释为八进制)
- 它使用一个
num\u simple\u fraction()
helper(未显示)——它反过来使用一个gcd()
helper(也未显示)——将结果转换为一个简单的分数
- 分子的log10()是通过计算小数点后标记的长度来确定的
这个简单的代码怎么样:
double n = 1.375;
int num = 1, den = 1;
double frac = (num * 1.f / den);
double margin = 0.000001;
while (abs(frac - n) > margin){
if (frac > n){
den++;
}
else{
num++;
}
frac = (num * 1.f / den);
}
我没有做太多的测试,这只是一个想法。我会分三步来做
1) 找到小数点,这样你就知道分母有多大了
2) 得到分子。这只是删除小数点的原始文本
3) 得到分母。如果没有小数点,分母是1。否则,分母为10^n,其中n是(现在已删除)小数点右侧的位数
struct fraction {
std::string num, den;
};
fraction parse(std::string input) {
// 1:
std::size_t dec_point = input.find('.');
// 2:
if (dec_point == std::string::npos)
dec_point = 0;
else {
dec_point = input.length() - dec_point;
input.erase(input.begin() + dec_point);
}
// 3:
int denom = 1;
for (int i = 1; i < dec_point; ++i)
denom *= 10;
string result = { input, std::to_string(denom) };
return result;
}
结构分数{
std::string num,den;
};
分数分析(标准::字符串输入){
// 1:
std::size\t dec\u point=input.find('.');
// 2:
if(dec_point==std::string::npos)
dec_点=0;
否则{
dec_point=input.length()-dec_point;
input.erase(input.begin()+dec_点);
}
// 3:
int-denom=1;
对于(int i=1;i
您并没有真正指定是否需要转换浮点或字符串与比率,因此我将假设为前者
您可以直接使用编码的属性,而不是尝试基于字符串或算术的方法
浮点(标准称为binary32
)在内存中编码如下:
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
^ ^
bit 31 bit 0
value = (-1)^S * significand * 2 ^ expoenent
where:
significand = 1.MMMMMMMMMMMMMMMMMMMMMMM (as binary)
exponent = EEEEEEEE (as binary) - 127
(-1)^S * significand * exponent = (-1)^s * (significand * 2^23) * 2 ^ (exponent - 23)
float fv = 1.375f;
Ratio rv = Ratio::fromFloat(fv);
std::cout << "fv = " << fv << ", rv = " << rv << ", rv.toFloat() = " << rv.toFloat() << "\n";
其中,S
是符号位,E
S是指数位(其中8位)M
S是尾数位(23位)
数字可以按如下方式解码:
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
^ ^
bit 31 bit 0
value = (-1)^S * significand * 2 ^ expoenent
where:
significand = 1.MMMMMMMMMMMMMMMMMMMMMMM (as binary)
exponent = EEEEEEEE (as binary) - 127
(-1)^S * significand * exponent = (-1)^s * (significand * 2^23) * 2 ^ (exponent - 23)
float fv = 1.375f;
Ratio rv = Ratio::fromFloat(fv);
std::cout << "fv = " << fv << ", rv = " << rv << ", rv.toFloat() = " << rv.toFloat() << "\n";
(注:这是所谓的“正常数”,也有零、次正常数、无穷和N-参见维基百科第一页链接)
这里可以用这个。我们可以这样重写上面的等式:
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
^ ^
bit 31 bit 0
value = (-1)^S * significand * 2 ^ expoenent
where:
significand = 1.MMMMMMMMMMMMMMMMMMMMMMM (as binary)
exponent = EEEEEEEE (as binary) - 127
(-1)^S * significand * exponent = (-1)^s * (significand * 2^23) * 2 ^ (exponent - 23)
float fv = 1.375f;
Ratio rv = Ratio::fromFloat(fv);
std::cout << "fv = " << fv << ", rv = " << rv << ", rv.toFloat() = " << rv.toFloat() << "\n";
关键是有效位*2^23
是一个整数(等于1.mmmmmmmmmmmmmmmm
,二进制-通过乘以2^23,我们将点向右移动了23位)。2^(指数-23)
显然也是一个整数
换句话说:我们可以将数字写为:
(significand * 2^23) / 2^(-(exponent - 23)) (when exponent - 23 < 0)
or
[(significand * 2^23) * 2^(exponent - 23)] / 1 (when exponent - 23 >= 0)
(有效位*2^23)/2^(-(指数-23))(当指数-23<0时)
或
[(有效位*2^23)*2^(指数-23)]/1(指数-23>=0时)
所以我们有分子和分母-直接来自数字的二进制表示
以上所有功能都可以在C++中实现:
struct Ratio
{
int64_t numerator; // numerator includes sign
uint64_t denominator;
float toFloat() const
{
return static_cast<float>(numerator) / denominator;
}
static Ratio fromFloat(float v)
{
// First, obtain bitwise representation of the value
const uint32_t bitwiseRepr = *reinterpret_cast<uint32_t*>(&v);
// Extract sign, exponent and mantissa bits (as stored in memory) for convenience:
const uint32_t signBit = bitwiseRepr >> 31u;
const uint32_t expBits = (bitwiseRepr >> 23u) & 0xffu; // 8 bits set
const uint32_t mntsBits = bitwiseRepr & 0x7fffffu; // 23 bits set
// Handle some special cases:
if(expBits == 0 && mntsBits == 0)
{
// special case: +0 and -0
return {0, 1};
}
else if(expBits == 255u && mntsBits == 0)
{
// special case: +inf, -inf
// Let's agree that infinity is always represented as 1/0 in Ratio
return {signBit ? -1 : 1, 0};
}
else if(expBits == 255u)
{
// special case: nan
// Let's agree, that if we get NaN, we returns max int64_t by 0
return {std::numeric_limits<int64_t>::max(), 0};
}
// mask lowest 23 bits (mantissa)
uint32_t significand = (1u << 23u) | mntsBits;
const int64_t signFactor = signBit ? -1 : 1;
const int32_t exp = expBits - 127 - 23;
if(exp < 0)
{
return {signFactor * static_cast<int64_t>(significand), 1u << static_cast<uint32_t>(-exp)};
}
else
{
return {signFactor * static_cast<int64_t>(significand * (1u << static_cast<uint32_t>(exp))), 1};
}
}
};
结构比率
{
int64\u t分子;//分子包含符号
uint64_t分母;
float toFloat()常量
{
返回静态类型(分子)/分母;
}
浮点数的静态比率(浮点数v)
{
//首先,获取值的按位表示
const uint32_t bitwiseRepr=*重新解释类型(&v);
//为方便起见,提取符号、指数和尾数位(存储在内存中):
constuint32\u t signBit=bitwiseRepr>>31u;
const uint32_t expBits=(bitwiseRepr>>23u)&0xffu;//设置8位
const uint32\u t mntsBits=bitwiseRepr&0x7fffffu;//设置23位
//处理一些特殊情况:
if(expBits==0&&mntsBits==0)
{
//特殊情况:+0和-0
返回{0,1};
}
else if(expBits==255u&&mntsBits==0)
{
//特殊情况:+inf,-inf
//让我们同意无穷大总是以1/0的比例表示
返回{signBit?-1:1,0};
}
else if(expBits==255u)
{
//特例:南
//让我们同意,如果得到NaN,则返回max int64\u t乘以0
返回{std::numeric_limits::max(),0};
}