如何获得十进制数的右侧,左侧的位数

时间:2014-02-10 21:50:52

标签: php math decimal

我想知道是否有一个很好的方法来获得十进制数PHP右/左侧的位数。例如:

12345.789 - >右侧长度 3 /左侧长度 5

我知道通过帮助string功能和爆炸数量可以轻松实现。我的意思是以数学或编程方式执行它比字符串操作更好。

非常感谢您的回答。

更新

到目前为止左侧的最佳解决方案是:

$left = floor(log10($x))+1;

但对于右侧仍然不够。 还在等......

5 个答案:

答案 0 :(得分:3)

要获取左侧的数字,您可以执行以下操作:

$left = floor(log10($x))+1;

这使用基数10的对数来获得位数。

右侧更难。一个简单的方法看起来像这样,但由于浮点数,它往往会失败:

$decimal = $x - floor($x);
$right = 0;
while (floor($decimal) != $decimal) {
    $right++;
    $decimal *= 10; //will bring in floating point 'noise' over time
}

这将循环乘以10,直到小数点后没有数字。这是使用floor($decimal) != $decimal测试的。

然而,正如Ali指出的那样,给它数字155.11(难以用二进制表示数字)会得到14的答案。这是因为数字存储为类似155.11000000000001的32位浮点精度我们有。

相反,需要一个更强大的解决方案。 (上面的PoPoFibo解决方案特别优雅,并且使用PHP继承了浮点比较函数)。

事实是,我们永远无法区分输入155.11和155.11000000000001。我们永远不会知道最初给出的是哪个号码。它们都代表相同。但是,如果我们在确定小数是“完成”之前定义了我们可以在一行中看到的零的数量,那么我们可以提出一个解决方案:

$x = 155.11; //the number we are testing

$LIMIT = 10; //number of zeroes in a row until we say 'enough'

$right = 0; //number of digits we've checked
$empty = 0; //number of zeroes we've seen in a row

while (floor($x) != $x) {
    $right++;

    $base = floor($x); //so we can see what the next digit is;
    $x *= 10;
    $base *= 10;

    $digit = floor($x) - $base; //the digit we are dealing with

    if ($digit == 0) {
        $empty += 1;
        if ($empty == $LIMIT) {
            $right -= $empty; //don't count all those zeroes
            break; // exit the loop, we're done
        }
    } else {
        $zeros = 0;
    }
} 

这应该找到解决方案,给出合理的假设,连续10个零意味着任何其他数字无关紧要。

然而,我仍然更喜欢PopoFibo的解决方案,因为没有任何乘法,PHP的默认比较函数有效地做同样的事情,没有混乱。

答案 1 :(得分:2)

我在PHP语义很大的时候迷失了,但我想以下会在没有使用String的情况下达到你的目的(至少我会用Java做什么,但希望更干净):

此处的工作代码:http://ideone.com/7BnsR3

非字符串解决方案(仅限数学)

左侧已解决,因此从您的问题更新中获取提示:

$value = 12343525.34541;
$left = floor(log10($value))+1;
echo($left);

$num = floatval($value); 
$right = 0;

while($num != round($num, $right)) {
  $right++;
}

echo($right);

打印

85
LHS为8,RHS为5。

因为我正在使用floatval将155.0作为0 RHS我认为是有效的并且可以通过字符串函数解析。

答案 2 :(得分:1)

php > $num = 12345.789;
php > $left = strlen(floor($num));
php > $right = strlen($num - floor($num));
php > echo "$left / $right\n";
5 / 16   <--- 16 digits, huh?
php > $parts = explode('.', $num);
php > var_dump($parts);
array(2) {
  [0]=>
  string(5) "12345"
  [1]=>
  string(3) "789"

正如您所看到的,浮动并不是最容易处理的......以“数学方式”执行它会导致不良结果。通过字符串来实现,但会让你觉得很脏。

答案 3 :(得分:1)

$number = 12345.789;

list($whole, $fraction) = sscanf($number, "%d.%d");

这将始终有效,即使$number是一个整数,您将获得两个返回的实数。即使对于整数值,最好使用strlen()来完成长度。正如您所料,建议的log10()方法不适用于10,100,1000 ......

// 5 - 3
echo strlen($whole) , " - " , strlen($fraction);

如果你真的,真的想在没有调用任何字符串函数的情况下获得长度,那么你去吧。但与strlen()相比,它完全没有效率。

/**
 * Get integer length.
 *
 * @param integer $integer
 *   The integer to count.
 * @param boolean $count_zero [optional]
 *   Whether 0 is to be counted or not, defaults to FALSE.
 * @return integer
 *   The integer's length.
 */
function get_int_length($integer, $count_zero = false) {
    // 0 would be 1 in string mode! Highly depends on use case.
    if ($count_zero === false && $integer === 0) {
        return 0;
    }
    return floor(log10(abs($integer))) + 1;
}

// 5 - 3
echo get_int_length($whole) , " - " , get_int_length($fraction);

以上内容将正确计算1 / 3的结果,但要注意精度很重要。

$number = 1 / 3;
// Above code outputs
// string : 1 - 10
// math   : 0 - 10

$number = bcdiv(1, 3);
// Above code outputs
// string : 1 - 0       <-- oops
// math   : 0 - INF     <-- 8-)

没问题。

答案 4 :(得分:0)

我想应用一个简单的逻辑。

<?php
$num=12345.789;
$num_str="".$num; // Converting number to string
$array=explode('.',$num_str); //Explode number (String) with .

echo "Left side length : ".intval(strlen($array[0])); // $array[0] contains left hand side then check the string length 
echo "<br>";
if(sizeof($array)>1)
{
echo "Left side length : ".intval(strlen($array[1]));// $array[1] contains left hand  check the string length side
}
?>