I'm trying to convert cents to dollars (I don't need dollar sign, just value) but when I divide a number smaller than 100 by 100 I get a strange result.
Eg.: 1/100 give me 0,01.0
I don't need that comma, I need 0.01 as it should be.
I also tried number_format but it returns a string and when I cast the result to float I get the same strange value.
How can I fix it?
Thanks in advance for your help
This is the function I'm using:
public static function convertFromCents($value) {
if(is_numeric($value)) {
$value = $value/100;
} else {
$value = 0;
}
return $value;
}
This are the proof of what I'm saying:
It looks like what you see are messages of your IDE, not the real value of your variable.
In order to achieve what you want, you can simply use round function.
The second parameter is precision, which determines how many digits will appear after the point:
// return 0.33333333333333
echo 1/3;
// return 0.33
echo round(1/3, 2);
Related
I know you can tell a variable to go to a certain number of decimal places using:
string number_format ( float $number [, int $decimals = 3 ] )
However, I cannot find a way of doing this en masse for all numbers. Since I have hundreds of variables, all of which need to have the same number of decimal places (whether it means rounding or extending zeros), I would like to be able to just tell it to automatically perform this command across the board instead of typing in the above command for all variables.
Does this function exist, or am I forced to type it all out the long way? Is there maybe a line in the .ini file that I could change if there is no command?
Thanks in advance.
I'm not storing these numbers in a database - I'm echo-ing them on the screen and sending an email.
(There is an equation going on from user input being generated by an HTML form).
The person receiving the email has asked that all numbers be rounded to the third decimal, whether that means rounding off at the thousandths or extending zeros to the thousandths if it only needed whole numbers, tenths, or hundredths. There are literally hundreds of individual variables, i.e. $number1, $number2, etc.
If you are talking about all numbers applied to string variables in your script you could run this line:
if(is_int($value) || is_float($value)){
$value = number_format ( float $number ,3 );
}
Obviously as you reference strings you can also run a similar query to check if your string is a floating numeric:
$values = get_defined_vars();
foreach ($values as $key=>$value){
if(is_string($value) && (float)$value == (string)$value){
$value = number_format ((float)$value , 3 );
}
/***
Save over the original script variables with the edited ones.
Note double dollar
***/
$$key = $value;
}
unset($values,$value,$key);
You could do with reading that in base-2 (computer storage) floating point numbers are inherently stored inaccurately, read http://floating-point-gui.de/ .
Also, really, why would you need this seemingly needless precision?
But then at what stage do you run this command, at the start of your script when the values are mostly empty? Or at the end when the values are mostly been used and no longer active?
I think my answer answers your question but I think that your question does not actually articulate your issue.
In response to the comment / edited qestion:
Simply rather than using $values = get_defined_vars(); use the values from saving the inputs into an array and doing foreach above through the array.
$values = array(array of numbers);
foreach ($values as &$value){
if(is_string($value) && (float)$value == (string)$value){
$value = number_format ((float)$value , 3 );
}
}
unset($value,$key);
This will update all values in the array to being of the spcified numerical placements.
You can use the decimal extension to achieve this, with a central place to create and format. Something like this:
class Number
{
public static function create($value, $precision = Decimal::DEFAULT_PRECISION): Decimal
{
return new Decimal($value, $precision);
}
public static function format(Decimal $decimal, int $places = 3): string
{
return $decimal->toFixed(3);
}
}
MySQL data imoprt mongo database.
price float(15,2) in mysql, mongo is not float(15,2).
I want to Determine a var $price have two decimal places.
eg. 100.00 is right, 100 or 100.0 is wrong.
eg.1
$price = 100.00;
$price have two decimal, it's right.
eg.2
$price = 100.0;
$price have not two decimal, it's wrong.
I like to use Regular Expressions to do these things
function validateTwoDecimals($number)
{
if(preg_match('/^[0-9]+\.[0-9]{2}$/', $number))
return true;
else
return false;
}
(Thanks to Fred-ii- for the corrections)
Everybody is dancing around the fact that floating point numbers don't have a number of decimal places in their internal representation. i.e. in float 100 == 100.0 == 100.00 == 100.000 and are all represented by the same number, effectively 100 and is stored that way.
The number of decimal places in this example only has a context when the number is represented as a string. In which case any string function that counts the number of digits trailing the decimal point could be used to check.
number_format($price, $numberOfDecimalDigits) === $price;
or
strrpos($price, '.') === strlen($price) - 1 - $numberOfDecimalDigits;
Trivia: $price should not be called a "float variable". This is a string that happens to represent a float value. 100.00 as a float has zero decimal digits, and 100.00 === 100 as float :
$price = 100.00;
echo $price; // output: 100
$price2 = (float)100;
echo $price === $price2; // ouput: 1
In order for this to work, the number will need to be wrapped in quotes.
With the many scripts I've tested, using $price = 100.00; without quotes did not work, while $price = 100.10; did, so this is as best as it gets.
<?php
$number = '100.00';
echo $number.'<br>';
$count = explode('.',$number);
echo 'The number of digits after the decimal point is: ' . strlen($count[1]);
if(strlen($count[1]) == 2){
echo "<br>";
echo "There is 2 decimal points.";
}
else{
echo "<br>";
echo "There is not 2 decimal points.";
}
After you format the value, you can check with simply splitting the value as string into 2 parts, for example with explode ...
$ex=explode('.',$in,2); if (strlen($ex[1])==2)
{
// true
}
else
{
// false
}
But again, as i've commented already, if you really have floating input, this is just not a reliable way, as floating numbers are without set decimal places, even if they appears so because of the rounding at the float=>string conversion
What you can do, if you really have floating numbers and wish to have xxx.yy format numbers:
1) convert float to string using round($x,2), so it will round to 2 decimal places.
2) explode the number as i've described, and do the following:
while (strlen($ex[1]<2)) {$ex[1].='0';}
$number=implode('.',$ex);
I would use the following function for that:
function isFloatWith2Decimals($number) {
return (bool) preg_match('/^(?:[1-9]{1}\d*|0)\.\d{2}$/', $number);
}
This will also check if you have only one leading 0 so number like 010.23 won't be considered as valid whereas number like 0.23 will.
And if you don't care about leading 0 you could use simpler method:
function isFloatWith2Decimals($number) {
return (bool) preg_match('/^\d+\.\d{2}$/', $number);
}
Of course numbers need to be passed as string - if you pass 100.00 won't be considered as true, whereas '100.00' will
I have two variables in a PHP program for billing statements, $charges and $payments.
$charges is the total amount due before any payments. $payments is the total amount received.
I calculate the balance due like so:
$balance_due = $charges-$payments;
Simple, except I am getting the following result:
$balance_due has -9.0949470177293E-13 for a value (expecting 0).
Both $charges and $payments have a value of 5511.53.
When I var_dump($charges) and var_dump($payments) they both show: float(5511.53)
This code (and === ):
if($charges == $payments){
error_log('they are the same');
}else{
error_log('they are not the same');
}
both result in false.
If I hard code: $charges = $payments = 5511.53; and run it then $balance_due = 0 as expected.
I am confused. What am I missing?
EDIT NOTES
I was able to use a user contributed function by Nitrogen found on the BC Math Functions page that was suggested I look at in order to come up with the following solution:
if(Comp($charges, $payments)===0){
$balance_due = 0;
}else{
$balance_due = ( $charges - $payments );
}
function Comp($Num1,$Num2,$Scale=null) {
// check if they're valid positive numbers, extract the whole numbers and decimals
if(!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num1,$Tmp1)||
!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num2,$Tmp2)) return('0');
// remove leading zeroes from whole numbers
$Num1=ltrim($Tmp1[1],'0');
$Num2=ltrim($Tmp2[1],'0');
// first, we can just check the lengths of the numbers, this can help save processing time
// if $Num1 is longer than $Num2, return 1.. vice versa with the next step.
if(strlen($Num1)>strlen($Num2)) return(1);
else {
if(strlen($Num1)<strlen($Num2)) return(-1);
// if the two numbers are of equal length, we check digit-by-digit
else {
// remove ending zeroes from decimals and remove point
$Dec1=isset($Tmp1[2])?rtrim(substr($Tmp1[2],1),'0'):'';
$Dec2=isset($Tmp2[2])?rtrim(substr($Tmp2[2],1),'0'):'';
// if the user defined $Scale, then make sure we use that only
if($Scale!=null) {
$Dec1=substr($Dec1,0,$Scale);
$Dec2=substr($Dec2,0,$Scale);
}
// calculate the longest length of decimals
$DLen=max(strlen($Dec1),strlen($Dec2));
// append the padded decimals onto the end of the whole numbers
$Num1.=str_pad($Dec1,$DLen,'0');
$Num2.=str_pad($Dec2,$DLen,'0');
// check digit-by-digit, if they have a difference, return 1 or -1 (greater/lower than)
for($i=0;$i<strlen($Num1);$i++) {
if((int)$Num1{$i}>(int)$Num2{$i}) return(1);
else
if((int)$Num1{$i}<(int)$Num2{$i}) return(-1);
}
// if the two numbers have no difference (they're the same).. return 0
return(0);
}
}
}
That solution worked for me. The answer provided by imtheman below also works and seems more efficient so I am going to use that one instead. Is there any reason not to use one or the other of these?
The way I solved this problem when I ran into it was using php's number_format(). From php documentation:
string number_format(float $number [, int $decimals = 0 ])
So what I would do is this:
$balance_due = number_format($charges-$payments, 2);
And that should solve your problem.
Note: number_format() will return a string, so to compare it you must use == (not ===) or cast it back into a (float) before comparison.
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.
I would like to know (as I current don't know and can't find the answer) how to turn a number without a decimal point into a number with a decimal point.
Here is what I would like to happen.
Input Output
1.20 1.20
1234 0.1234
0.23456 0.23456
4321 0.4321
So basically I need a PHP function that accepts an input number (from a form field, variable or whatever) and if a whole number add 0. (zero dot) to the beginning. If the input number already has a decimal leave as is (I will number_format afterwards).
This simple solution should do it.
function to_decimal($in){
return (stripos($in, ".")!==false)? $in: "0.".$in;
}
You could do something like this with is_float
if (!is_float($input))
{
$result = "0." . $input
}
Try this
function dPoint($number)
{
if(is_float($number))
{
return $number;
}
else
{
return "0.".$number;
}
}
Here's my solution without lame string concatenation
function leadingZero($num) {
if (!ctype_digit($num)) {
return $num/pow(10, strlen($num));
}
return $num;
}
// php> =leadingZero(4652)
// 0.4652
// php> =leadingZero(0.2)
// 0.2