我想知道是否有一个很好的方法来获得十进制数PHP右/左侧的位数。例如:
12345.789
- >右侧长度 3 /左侧长度 5
我知道通过帮助string
功能和爆炸数量可以轻松实现。我的意思是以数学或编程方式执行它比字符串操作更好。
非常感谢您的回答。
更新
到目前为止左侧的最佳解决方案是:
$left = floor(log10($x))+1;
但对于右侧仍然不够。 还在等......
答案 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
}
?>