PHP detect and remove unnecessary cent of price [duplicate] - php

This question already has answers here:
Closed 10 years ago.
For invoicing I want to determine if my total amount has an unnecessary cent. e.g. $5.01 or $5.51. If it detects the cent then I run an if statement to remove the cent: minus 0.01
eg.
Change 30.51 to 0.01 and give a warning message
and also
30.51 to 0.51
and also
30.51 to 1
Both come from a POST, so they are both PHP strings.
but no worries - i got it to work now thanks to dmayo
$pieces = explode(".", $TotalAmt);
echo "<br>p1:".$pieces[1]; // piece2
$p1 = $pieces[1];
$spl1 = str_split($p1);
$TAmttmp = 0;
//echo "<br>sp11:".$spl1; // error convert array to string
$TAmttmp = $spl1[0];
echo "<br>TAmttmp: with useless cent".$TAmttmp;
echo "<br>IT:".$IT;
if ($TAmttmp == 0.01) //so if there is 1 cent subtract the useless cent.
$TAmt = $TAmt - 0.01;
echo "<br>TAmt: with useless cent".$TAmt;
echo "<br>TAmt: without useless cent".$TAmt;

#Gumbo is right, we need to know the logic behind your conversions to provide a precise answer.
You could do an explode:
$var = explode('.',$_POST['val']);
$digits = $var[1]; // this will give you the digits after the decimal point
Now you can do what you need based on your logic.
You could also you use a substr() where you find the decimal point (is it always three places from the right?) and then grab the substring.
Not sure which would be more efficient.

I don't know exactly what you want, but perhaps that helps:
$nr = "30.51";
echo round($nr - floor($nr), 2); // 0.51
echo round(($nr * 10 - floor($nr * 10)) / 10, 2); // 0.01
echo round(($nr * 10 - floor($nr * 10)) * 10); // 1

Related

Is there any way to regex and delete after a certain point in a decimal number in PHP? [duplicate]

This question already has answers here:
PHP How do I round down to two decimal places? [duplicate]
(16 answers)
Closed 4 years ago.
Is there any way to do a regex that cuts off a number at a certain point without rounding (simply drops the digits?) say after 4 digits.... It will not be handling negative numbers, EVER. I could have number inputs such as 0.03123 or 1.31, or 10000.98, etc .... What I have written so far as my solution is rounding and not what I'm seeking....
$number = 10000.51999999;
$precision = 4;
echo "<br>";
// grab number before decimal by rounding down the whole number down...
$numberBeforeDecimal = floor($number);
echo "<br>";
// grab the decimal and set the correct precision needed
$n = $number;
intval($n); // 12
$theDecimalPart = explode('.', number_format($n, ($precision)))[1]; // 3430
echo $theDecimalPart; // this is outputting 5200
$theNewValue = $numberBeforeDecimal.".".$theDecimalPart;
explode() the number to get integer and decimal part separated out in an array
Use substr() function to get relevant precision from the decimal part.
Finally, concatenate them back.
Try the following (Rextester DEMO):
$number = 10000.51999999;
$precision = 4;
// separate out the integer and decimal part
$number_str_arr = explode('.', $number);
// concatenate them back
$theNewValue = $number_str_arr[0] . '.' . substr($number_str_arr[1], 0, $precision);
echo $theNewValue; // displays 10000.5199

How to convert 11,22,33 into 10, 20 and 30 in PHP?

I don't know how to title the question correctly (please tell me what this kind of number called).
I'd like to convert from 2 digits number into a 10 divisible number. For example, I expect:
15 to become 10
23 to become 20
38 to become 30
999 to become 900
9999 to become 9000
I tried searching for the solution on google but I don't know how to type the proper word.
Easy, use the PHP floor function: http://php.net/manual/en/function.floor.php
floor($number/10) * 10
I wrote a simple function should work:
<?php
function roundDown($var){
$len = strlen($var)-1;
$divide = 1;
for($i=1;$i<=$len;$i++){
$divide .= 0;
}
return floor($var/$divide)*$divide;
}
echo roundDown(9999);
Easiest way is divide by ten, then floor value and multiply by ten. (Floor method - phpdocs)
floor($number/10)*10
Use round:
echo round(1241757, -6); // 1000000
from http://php.net/manual/en/function.round.php
You are looking for the "one significant figure".
I think this answer provides a good solution:
How to round down to the nearest significant figure in php
Short form:
$x = $y - $y % pow(10, floor(log10($y)));

How to get number of digits in both right, left sides of a decimal number

I wonder if is there a good way to get the number of digits in right/left side of a decimal number PHP. For example:
12345.789 -> RIGHT SIDE LENGTH IS 3 / LEFT SIDE LENGTH IS 5
I know it is readily attainable by helping string functions and exploding the number. I mean is there a mathematically or programmatically way to perform it better than string manipulations.
Your answers would be greatly appreciated.
Update
The best solution for left side till now was:
$left = floor(log10($x))+1;
but still no sufficient for right side.
Still waiting ...
To get the digits on the left side you can do this:
$left = floor(log10($x))+1;
This uses the base 10 logarithm to get the number of digits.
The right side is harder. A simple approach would look like this, but due to floating point numbers, it would often fail:
$decimal = $x - floor($x);
$right = 0;
while (floor($decimal) != $decimal) {
$right++;
$decimal *= 10; //will bring in floating point 'noise' over time
}
This will loop through multiplying by 10 until there are no digits past the decimal. That is tested with floor($decimal) != $decimal.
However, as Ali points out, giving it the number 155.11 (a hard to represent digit in binary) results in a answer of 14. This is because as the number is stored as something like 155.11000000000001 with the 32 bits of floating precision we have.
So instead, a more robust solution is needed. (PoPoFibo's solutions above is particularly elegant, and uses PHPs inherit float comparison functions well).
The fact is, we can never distinguish between input of 155.11 and 155.11000000000001. We will never know which number was originally given. They will both be represented the same. However, if we define the number of zeroes that we can see in a row before we just decide the decimal is 'done' than we can come up with a solution:
$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;
}
}
This should find the solution given the reasonable assumption that 10 zeroes in a row means any other digits just don't matter.
However, I still like PopoFibo's solution better, as without any multiplication, PHPs default comparison functions effectively do the same thing, without the messiness.
I am lost on PHP semantics big time but I guess the following would serve your purpose without the String usage (that is at least how I would do in Java but hopefully cleaner):
Working code here: http://ideone.com/7BnsR3
Non-string solution (only Math)
Left side is resolved hence taking the cue from your question update:
$value = 12343525.34541;
$left = floor(log10($value))+1;
echo($left);
$num = floatval($value);
$right = 0;
while($num != round($num, $right)) {
$right++;
}
echo($right);
Prints
85
8 for the LHS and 5 for the RHS.
Since I'm taking a floatval that would make 155.0 as 0 RHS which I think is valid and can be resolved by String functions.
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"
As you can see, floats aren't the easiest to deal with... Doing it "mathematically" leads to bad results. Doing it by strings works, but makes you feel dirty.
$number = 12345.789;
list($whole, $fraction) = sscanf($number, "%d.%d");
This will always work, even if $number is an integer and you’ll get two real integers returned. Length is best done with strlen() even for integer values. The proposed log10() approach won't work for 10, 100, 1000, … as you might expect.
// 5 - 3
echo strlen($whole) , " - " , strlen($fraction);
If you really, really want to get the length without calling any string function here you go. But it's totally not efficient at all compared to 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);
The above will correctly count the result of 1 / 3, but be aware that the precision is important.
$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-)
No problem there.
I would like to apply a simple logic.
<?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
}
?>

PHP how to show all decimal places?

this might be a stupid question but I have searched again and again without finding any results.
So, what I want is to show all the decimal places of a number without knowing how many decimal places it will have. Take a look at this small code:
$arrayTest = array(0.123456789, 0.0123456789);
foreach($arrayTest as $output){
$newNumber = $output/1000;
echo $newNumber;
echo "<br>";
}
It gives this output:
0.000123456789
1.23456789E-5
Now, I tried using 'number_format', but I don't think that is a good solution. It determines an exact amount of decimal places, and I do not know the amount of decimal places for every number. Take a look at the below code:
$arrayTest = array(0.123456789, 0.0123456789);
foreach($arrayTest as $output){
$newNumber = $output/1000;
echo number_format($newNumber,13);
echo "<br>";
}
It gives this output:
0.0001234567890
0.0000123456789
Now, as you can see there is an excess 0 in the first number, because number_format forces it to have 13 decimal places.
I would really love some guidance on how to get around this problem. Is there a setting in PHP.ini which determines the amount of decimals?
Thank you very much in advance!
(and feel free to ask if you have any further questions)
It is "impossible" to answer this question properly - because a binary float representation of a decimal number is approximate: "What every computer scientist should know about floating point"
The closest you can come is write yourself a routine that looks at a decimal representation of a number, and compares it to the "exact" value; once the difference becomes "small enough for your purpose", you stop adding more digits.
This routine could then return the "correct number of digits" as a string.
Example:
<?php
$a = 1.234567890;
$b = 0.123456789;
echo returnString($a)."\n";
echo returnString($b)."\n";
function returnString($a) {
// return the value $a as a string
// with enough digits to be "accurate" - that is, the value returned
// matches the value given to 1E-10
// there is a limit of 10 digits to cope with unexpected inputs
// and prevent an infinite loop
$conv_a = 0;
$digits=0;
while(abs($a - $conv_a) > 1e-10) {
$digits = $digits + 1;
$conv_a = 0 + number_format($a, $digits);
if($digits > 10) $conv_a = $a;
}
return $conv_a;
}
?>
Which produces
1.23456789
0.123456789
In the above code I arbitrarily assumed that being right to within 1E-10 was good enough. Obviously you can change this condition to whatever is appropriate for the numbers you encounter - and you could even make it an optional argument of your function.
Play with it - ask questions if this is not clear.

PHP rounding error with simple multiplication [duplicate]

This question already has answers here:
Is floating point math broken?
(31 answers)
Closed 3 years ago.
PHP seems to round incorrectly when using (int) to cast variables. Why?
$multiplier = 100000000;
$value = 0.01020637;
echo (int)($value*$multiplier);
Output: 1020636. (unexpected output)
$multiplier = 100000000;
$value = 0.01020637;
echo ($value*$multiplier);
Output: 1020637. (Expected correct output)
Edit: it gets even worse...
$multiplier = 100000000;
$value = 0.01020637;
echo $temp = ($value*$multiplier);
echo '<br/>';
echo (int)$temp;
Output:
1020637
1020636
Things can get hairy when you're dealing with floats, floating point math (and problems involved) are well understood, but can crop up when you're not expecting them. As seems to have happened here. You could read up on the rules extensively, or use language provided tools when handling floating point arithmetic.
When you care about the precision involved you should use the bcmul() function. It's an "optional" extension, but if you care about precision it starts being required rather quickly.
Example:
multiplier = 100000000;
$value = 0.01020637;
echo (int)($value*$multiplier);
echo "\n";
echo bcmul($value, $multiplier, 0);
Sample: http://ideone.com/Wt9kKb
PHP (especially in 32 bit builds) has problems with floating point numbers. This is why casting float into int can have unpredictable results. See PHP Integer page for more detail. Basically, you're getting tiny imprecisions in the math and that can cause serious problems when trying to do something like ceil()
If you really need the numbers converted to int I would suggest you round the numbers first
$multiplier = 100000000;
$value = 0.01020637;
$temp = round($value*$multiplier);
echo $temp . '<br/>' . (int)$temp;
This works by truncating off the small floating point errors. While bcmath can also do the truncation, it's not part of PHP core and not a good overall solution. Your best bet is to write a rounding routine yourself that can return the precision you're looking for. In the project I work on, that was what we did. We wrote our own rounding function and it fixes the problems you'll run into. Without knowing the specifics of what you're trying to do it's hard to say if that's what you need but it's how we did it without bcmath.
The problem you're seeing is the following:
When multiplying two numbers like this:
$mulitply = 0.1 * 100;
You are not multiplying exactly 100 with 0.1, but with with 0.09999999998...
And when it comes to (int), it converts numbers like 4.999 to 4, so your result 1020636.999999999 becomes 1020636 when counting with (int).
bcmul allows for higher precision
$test = (int) bcmul('100000000', '0.01020637');
echo $test
returns the correct answer.
To round floats in PHP you should use the round() function. Just casting to an integer does not round the value correctly.
First argument is which float (the result of your calculation in this case) to be rounded, second is optional, and specifies the amount of decimals (aka precision) being returned. There is also a third argument, controlling the mode. These can be PHP_ROUND_HALF_UP, PHP_ROUND_HALF_DOWN, PHP_ROUND_HALF_EVEN or PHP_ROUND_HALF_ODD.
Example from php.net/round:
<?php
echo round(3.4); // 3
echo round(3.6); // 4
echo round(3.6, 0); // 4
echo round(1.95583, 2); // 1.96
// With the third element, "mode"
echo round(9.5, 0, PHP_ROUND_HALF_UP); // 10
echo round(9.5, 0, PHP_ROUND_HALF_DOWN); // 9
echo round(9.5, 0, PHP_ROUND_HALF_EVEN); // 10
echo round(9.5, 0, PHP_ROUND_HALF_ODD); // 9
?>
An example for your code (live example):
<?php
$multiplier = 100000000;
$value = 0.01020637;
echo intval(round($value*$multiplier)); // Returns 1020637
?>

Categories