php PHP将小数转换为分数并返回?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1954018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
PHP convert decimal into fraction and back?
提问by JD Isaacks
I want the user to be able to type in a fraction like:
我希望用户能够输入一个分数,如:
1/2
2 1/4
3
And convert it into its corresponding decimal, to be saved in MySQL, that way I can order by it and do other comparisons to it.
并将其转换为相应的十进制,以保存在MySQL中,这样我就可以通过它进行排序并对其进行其他比较。
But I need to be able to convert the decimal back to a fraction when showing to the user
但是我需要能够在向用户显示时将小数转换回分数
so basically I need a function that will convert fraction string to decimal:
所以基本上我需要一个将分数字符串转换为十进制的函数:
fraction_to_decimal("2 1/4");// return 2.25
and a function that can convert a decimal to a faction string:
以及一个可以将小数转换为派系字符串的函数:
decimal_to_fraction(.5); // return "1/2"
How can I do this?
我怎样才能做到这一点?
采纳答案by Derek Illchuk
I think I'd store the string representation too, as, once you run the math, you're not getting it back!
我想我也会存储字符串表示,因为一旦你运行数学,你就不会得到它!
And, here's a quick-n-dirty compute function, no guarantees:
而且,这是一个快速n-dirty计算函数,不能保证:
$input = '1 1/2';
$fraction = array('whole' => 0);
preg_match('/^((?P<whole>\d+)(?=\s))?(\s*)?(?P<numerator>\d+)\/(?P<denominator>\d+)$/', $input, $fraction);
$result = $fraction['whole'] + $fraction['numerator']/$fraction['denominator'];
print_r($result);die;
Oh, for completeness, add a check to make sure $fraction['denominator'] != 0.
哦,为了完整性,添加一个检查以确保$fraction['denominator'] != 0.
回答by mmcconkie
Sometimes you need to find a way to do it and rounding is acceptable. So if you decide what range of rounding works out for you you can build a function like this. To convert a decimal into the fraction that it most closely matches. You can extend the accuracy by adding more denominators to be tested.
有时你需要找到一种方法来做到这一点,四舍五入是可以接受的。因此,如果您决定适合您的四舍五入范围,您可以构建这样的函数。将小数转换为最接近匹配的分数。您可以通过添加更多要测试的分母来扩展准确度。
function decToFraction($float) {
// 1/2, 1/4, 1/8, 1/16, 1/3 ,2/3, 3/4, 3/8, 5/8, 7/8, 3/16, 5/16, 7/16,
// 9/16, 11/16, 13/16, 15/16
$whole = floor ( $float );
$decimal = $float - $whole;
$leastCommonDenom = 48; // 16 * 3;
$denominators = array (2, 3, 4, 8, 16, 24, 48 );
$roundedDecimal = round ( $decimal * $leastCommonDenom ) / $leastCommonDenom;
if ($roundedDecimal == 0)
return $whole;
if ($roundedDecimal == 1)
return $whole + 1;
foreach ( $denominators as $d ) {
if ($roundedDecimal * $d == floor ( $roundedDecimal * $d )) {
$denom = $d;
break;
}
}
return ($whole == 0 ? '' : $whole) . " " . ($roundedDecimal * $denom) . "/" . $denom;
}
回答by codaddict
To can use PEAR's Math_Fraction class for someof your needs
可以使用 PEAR 的 Math_Fraction 类来满足您的一些需求
<?php
include "Math/Fraction.php";
$fr = new Math_Fraction(1,2);
// print as a string
// output: 1/2
echo $fr->toString();
// print as float
// output: 0.5
echo $fr->toFloat();
?>
回答by Eric Anderson
Here is a solution that first determines a valid fraction (although not necessarily the simplest fraction). So 0.05 -> 5/100. It then determines the greatest common divisor of the numerator and denominator to reduce it down to the simplest fraction, 1/20.
这是一个首先确定有效分数的解决方案(尽管不一定是最简单的分数)。所以 0.05 -> 5/100。然后确定分子和分母的最大公约数以将其减少到最简单的分数 1/20。
function decimal_to_fraction($fraction) {
$base = floor($fraction);
$fraction -= $base;
if( $fraction == 0 ) return $base;
list($ignore, $numerator) = preg_split('/\./', $fraction, 2);
$denominator = pow(10, strlen($numerator));
$gcd = gcd($numerator, $denominator);
$fraction = ($numerator / $gcd) . '/' . ($denominator / $gcd);
if( $base > 0 ) {
return $base . ' ' . $fraction;
} else {
return $fraction;
}
}
# Borrowed from: http://www.php.net/manual/en/function.gmp-gcd.php#69189
function gcd($a,$b) {
return ($a % $b) ? gcd($b,$a % $b) : $b;
}
This includes a pure PHP implementation of the gcd although if you are sure the gmp module is installed you could use the one that comes with gcd.
这包括 gcd 的纯 PHP 实现,但如果您确定安装了 gmp 模块,则可以使用 gcd 附带的模块。
As many others have noted you need to use rational numbers. So if you convert 1/7 to a decimal then try to convert it back to a decimal you will be out of luck because the precision lost will prevent it from getting back to 1/7. For my purposes this is acceptable since all the numbers I am dealing with (standard measurements) are rational numbers anyway.
正如许多其他人所指出的那样,您需要使用有理数。因此,如果您将 1/7 转换为小数,然后尝试将其转换回小数,您将不走运,因为精度损失将阻止它回到 1/7。就我而言,这是可以接受的,因为我正在处理的所有数字(标准测量值)无论如何都是有理数。
回答by Marlon Pascoal
Buddies, can this help?
朋友,这个能帮上忙吗?
[]s
[] 秒
function toFraction($number) {
if (!is_int($number)) {
$number = floatval($number);
$denominator = round(1 / $number);
return "1/{$denominator}";
}
else {
return $number;
}
}
回答by doublejosh
Little improvement on above, but keepin it simple.
上面的改进不大,但保持简单。
function dec2frac($f) {
$base = floor($f);
if ($base) {
$out = $base . ' ';
$f = $f - $base;
}
if ($f != 0) {
$d = 1;
while (fmod($f, 1) != 0.0) {
$f *= 2;
$d *= 2;
}
$n = sprintf('%.0f', $f);
$d = sprintf('%.0f', $d);
$out .= $n . '/' . $d;
}
return $out;
}
回答by Frederik Krautwald
function dec2frac($f)
{
$d = 1
while (fmod($f, 1) != 0.0) {
$f *= 2;
$d *= 2;
}
$n = sprintf('%.0f', $f);
$d = sprintf('%.0f', $d);
return array($n, $d);
}
Then $f == $n / $d
然后 $f == $n / $d
For example:
例如:
print_r(dec2frac(3.1415926));
Outputs:
输出:
Array
(
[0] => 3537118815677477 // $n
[1] => 1125899906842624 // $d
)
回答by Jir
An approach would be to retrieve the decimal value and multiply it by 2, 3, 4 and so on until you get an integer number.
一种方法是检索十进制值并将其乘以 2、3、4 等,直到得到整数。
However, I'd stick with the answer given by Derek. Guess what happens when a user inserts n/(n+1) with n high. Such an algorithm would have to scan all the numbers up to n+1. Not to mention it is likely you'll end up with approximation problems.
但是,我会坚持德里克给出的答案。猜猜当用户插入 n/(n+1) 和 n 高时会发生什么。这样的算法必须扫描直到 n+1 的所有数字。更不用说你最终可能会遇到近似问题。
回答by Arno
You'll have to face a serious problem, because floats are not precise enough.
你将不得不面对一个严重的问题,因为浮点数不够精确。
When you'll have to deal with 1.3333, PHP will make an estimate of this value... So you will never be able to convert it to 1 1/3.
当你要处理1.3333,PHP将使这个值的估计......所以,你将永远无法将其转换为1 1/3。
It seems to be simple to overcome, but if you want your program to differentiate 1/7901(~ 1,2656625743576762435134793064169e-4) with 1/7907(~
1,2647021626406981155937776653598e-4) precisely... this will be a real hell !!
克服它似乎很简单,但是如果您希望您的程序将1/7901( ~ 1,2656625743576762435134793064169e-4) 与1/7907( ~
1,2647021626406981155937776653598e-4) 精确区分......这将是一个真正的地狱!
IMHO, if you want to deal with maths, you should rely on an external library... or try to make PHP communicate with Matlab.
恕我直言,如果你想处理数学,你应该依赖一个外部库......或者尝试让 PHP 与 Matlab 进行通信。
If you want to know more, i suggest you dig in floating point problems... Starting with wikipedia.
如果您想了解更多,我建议您深入研究浮点问题...从维基百科开始。
回答by DrYak
A variation of Jir's approach could actually work if only a limited amount of denominators are used : multiply everything by the least common denominators (and round the result to discard any remaining decimals due to approximation).
如果只使用有限数量的分母,Jir 方法的变体实际上可以起作用:将所有内容乘以最小公分母(并将结果四舍五入以丢弃由于近似值而产生的任何剩余小数)。
I.e.: if you only have to deal with halfs, thrids and quarters, just multiply everything by 12.
即:如果您只需要处理一半、三次和四分之一,只需将所有内容乘以 12。
And also if you know the common denominator, this should greatly reduce the search speed by knowing exactly which numbers to search instead of searching all n+1 possible.
而且,如果您知道公分母,那么通过确切地知道要搜索哪些数字而不是搜索所有 n+1 可能会大大降低搜索速度。
If you have to deal with lots of unusual fractions, like 1/7, 1/13, etc. well, stick to Derek's solution and store the original value too.
如果您必须处理许多不寻常的分数,例如 1/7、1/13 等,请坚持使用 Derek 的解决方案并存储原始值。

