如何从小数获取分子和分母?例如,我希望从“ 1.375”得到“ 1375/1000”或“ 11/8”。我如何用C ++做到这一点? 我试图通过将点之前和之后的数字分开来做到这一点,但是它并不清楚如何获得所需的输出。
答案 0 :(得分:1)
在C ++中,您可以使用Boost有理类。但是您需要给出分子和分母。
为此,您需要找出小数点后的输入字符串中没有数字。您可以通过字符串操作函数来执行此操作。逐字符读取输入的字符,并在.
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.
答案 1 :(得分:0)
我希望发布一个仅使用“ C
语言”的答案得到原谅。我知道您用C++
标记了这个问题-但抱歉,我无法拒绝。至少C++
仍然有效(尽管它确实主要使用C字符串处理技术)。
int num_string_float_to_rat(char *input, long *num, long *den) {
char *tok = NULL, *end = NULL;
char buf[128] = {'\0'};
long a = 0, b = 0;
int den_power = 1;
strncpy(buf, input, sizeof(buf) - 1);
tok = strtok(buf, ".");
if (!tok) return 1;
a = strtol(tok, &end, 10);
if (*end != '\0') return 2;
tok = strtok(NULL, ".");
if (!tok) return 1;
den_power = strlen(tok); // Denominator power of 10
b = strtol(tok, &end, 10);
if (*end != '\0') return 2;
*den = static_cast<int>(pow(10.00, den_power));
*num = a * *den + b;
num_simple_fraction(num, den);
return 0;
}
示例用法:
int rc = num_string_float_to_rat("0015.0235", &num, &den);
// Check return code -> should be 0!
printf("%ld/%ld\n", num, den);
输出:
30047/2000
在http://codepad.org/CFQQEZkc处的完整示例。
注释:
strtok()
用于将输入解析为令牌(在这方面无需重新发明轮子)。 strtok()
修改其输入-因此为了安全起见,使用了临时缓冲区strtol()
代替atoi()
-因为它可以检测输入中的非数字字符scanf()
未使用 进行输入处理strtol()
的基数已明确设置为10
,以避免出现前导零的问题(否则前导零将导致数字被解释为八进制)num_simple_fraction()
帮助程序(未显示)-反过来使用gcd()
帮助程序(也未显示)-将结果转换为简单的分数答案 2 :(得分:0)
这个简单的代码呢?
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);
}
我并没有进行太多测试,这只是一个主意。
答案 3 :(得分:0)
我将分三个步骤进行操作。
1)找到小数点,以便知道分母必须多大。
2)获取分子。那只是去除小数点的原始文本。
3)获得分母。如果没有小数点,则分母为1。否则,分母为10 ^ n,其中n是(已删除的)小数点右边的位数。
WebView webview = new WebView(this);
setContentView(webview);
webview.loadUrl("https://myurl.com/");
webview.setWebViewClient(new MyWebViewClient());
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Toast.makeText(LoginActivityWebView.this, url, Toast.LENGTH_SHORT).show();
return false;
}
}
答案 4 :(得分:0)
您并没有真正指定是否需要将浮点数或字符串转换为比率,所以我将假设是前一个。
您可以直接使用IEEE-754编码的属性,而不必尝试使用基于字符串或基于算术的方法。
浮点数(按标准称为binary32
)在内存中的编码方式如下:
S EEEEEEEE MMMMMMMMMMMMMMMMMMMMMMM
^ ^
bit 31 bit 0
其中S
是符号位,E
是指数位(其中8个)M
是尾数位(23位)。
数字可以这样解码:
value = (-1)^S * significand * 2 ^ expoenent
where:
significand = 1.MMMMMMMMMMMMMMMMMMMMMMM (as binary)
exponent = EEEEEEEE (as binary) - 127
(注意:这是所谓的“正常数”,也有零,次正规数,无穷大和NaN-参见我链接的维基百科页面)
可以在这里使用。我们可以这样重写上面的等式:
(-1)^S * significand * exponent = (-1)^s * (significand * 2^23) * 2 ^ (exponent - 23)
问题在于significand * 2^23
是一个整数(等于1.MMMMMMMMMMMMMMMMMMMMMMM
,二进制-通过乘以2 ^ 23,我们将点右移了23位)。2 ^ (exponent - 23)
是一个整数显然也是。
换句话说:我们可以将数字写为:
(significand * 2^23) / 2^(-(exponent - 23)) (when exponent - 23 < 0)
or
[(significand * 2^23) * 2^(exponent - 23)] / 1 (when exponent - 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};
}
}
};
(希望上面的评论和描述是可以理解的,如果有需要改进的地方,请告诉我)
为简单起见,我省略了检查超出范围的值。
我们可以这样使用它:
float fv = 1.375f;
Ratio rv = Ratio::fromFloat(fv);
std::cout << "fv = " << fv << ", rv = " << rv << ", rv.toFloat() = " << rv.toFloat() << "\n";
输出为:
fv = 1.375,rv = 11534336/8388608,rv.toFloat()= 1.375
如您所见,两端的值完全相同。
问题在于分子和分子的数量很大。这是因为代码总是将有效数乘以2 ^ 23,即使较小的值足以使它成为整数(这等同于将0.2写为2000000/10000000而不是2/10-这是同一件事,只是写法不同)
这可以通过更改代码以将有效数(除以指数)乘以最小数来解决,如下所示(省略号代表与上述相同的部分):
// counts number of subsequent least significant bits equal to 0
// example: for 1001000 (binary) returns 3
uint32_t countTrailingZeroes(uint32_t v)
{
uint32_t counter = 0;
while(counter < 32 && (v & 1u) == 0)
{
v >>= 1u;
++counter;
}
return counter;
}
struct Ratio
{
...
static Ratio fromFloat(float v)
{
...
uint32_t significand = (1u << 23u) | mntsBits;
const uint32_t nTrailingZeroes = countTrailingZeroes(significand);
significand >>= nTrailingZeroes;
const int64_t signFactor = signBit ? -1 : 1;
const int32_t exp = expBits - 127 - 23 + nTrailingZeroes;
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};
}
}
};
现在,对于以下代码:
float fv = 1.375f;
Ratio rv = Ratio::fromFloat(fv);
std::cout << "fv = " << fv << ", rv = " << rv << ", rv.toFloat() = " << rv.toFloat() << "\n";
我们得到:
fv = 1.375,rv = 11/8,rv.toFloat()= 1.375