I'm creating an import based on xml. From the XML i get some values wich are negative amounts like -316.65.
Before I save this values to the database I have to convert them to positive amounts. I've tried the following:
$amount = $inkoopfactuur->td[7] * -1;
This worked but, the decimals where gone.
Is there a way to convert this witouth losing the decimals?
Thanks in advance!
There's a better way to do this:
$amount = abs($inkoopfactuur->td[7]);
However, it could be the case that the integer rounding is the result of something else -- there's not enough information in the question to be certain.
You probably have a different locale.
Check localeconv
Related
I'm developing a e-commerce and I have a problem when I want to format a number with number_format().
I have to set to my Stripe connection a number without decimals, so when I do all the calculations to have the final price of my shoppingcart I do:
$final_amount = number_format($final_amount, 2) * 100;
The result is a number that Stripe understands. I haven't got any problem with small numbers (like 970.25 or 1300.75 for example) but when I have a big amount like 15717.72 php throws the error "A non well formed numeric value encountered". I don't know if this is the problem, big numbers.
I've tried to parse previously $final_amount with floatval() and It didn't run either.
Someone knows the problem? thanks :)
A couple notes.
"A non well formed numeric value encountered" is a Notice, not an Error.
I don't believe 1300.75 works for you. The reason I don't believe this is you are only giving number_format two parameters. You are receiving that notice because number_format is formatting your number with a thousands separator ",".
$final_amount = number_format($final_amount, 2, ".", "") * 100;
should do the trick to remove that notice.
problem is not number_format() function but your calculation. You are multiplying a string with an integer. That does not work out so well.
$final_amount = number_format($final_amount * 100, 2);
Works just fine.
Update:
My conclusion was not completely correct. Multiplying an int with an string does work if the string is castable to int or float (see type juggling in PHP manual). But the string created by number_format() looks like this: "15,717.72". And thus cannot be cast to a number type.
I am trying to make this calculation in php but is giving me wrong result. I think that is right.
And if i do 5000.00 - 100.10 it works, but i want the 5,000.00 to work too.
This is my code:
To create the 5,000.00 i have used number_format(5000, 2).
Aswell to the 100.10
$total = $value1 - $value2;
echo $total;
?>
$total = -95.00
I am trying to make this calculation in php but is giving me wrong result. I think that is right.
And if i do 5000.00 - 100.10 it works, but i want the 5,000.00 to work too.
Please Help...
If you want to do arithmetic on number, you can't have the thousands separator (,). What's happening is 5,000.00 is being read as 5 (it stops interpreting it as a number as soon as it hits the comma) and then you're getting 5 - 100.10 which is -95.10 (I'm thinking you left off the .10 in your example.
You'll need to convert first:
$value1 = floatval(str_replace(',', '', $original_value1))
$value2 = floatval(str_replace(',', '', $original_value2))
I'm assuming here that you have them as strings originally. These remove the comma separator.
It sounds like you're confusing rendering in the UI with calculations.
It's perfectly reasonable for a user to see currencies rendered according to their locale rules (e.g. a String "$1,000.00" in USA), but the calculations in the back need to done on a floating point number (e.g. 1000.0).
So you have to be able to convert back and forth between them. You can't make arithmetic operations work on a String. Better to parse the String to a float, do the operations, then convert that back to String for rendering.
This is killing me! I've never had so much trouble and I can't figure out what I'm doing wrong here.
If I have a number, say 2.32, and I want to do math with it it won't work out. The very simplest example:
$income = $commission; //Commission is 2.32, retrieved from XML
echo "income: $income<br>";
$income100 = $income*100;
echo "income100: $income100<br>";
The result I get is:
income: 2.32
income100: 200
How can I use a decimal number accurately with math without it changing it?
Thanks so much!
You need to assign $income in the following manner to get rid of the underlying SimpleXMLElement:
$income = (float) $commission;
Example of what happens when you don't:
$x = simplexml_load_string("<a>2.4</a>");
echo $x * 100; // output: 200
Besides using floats as Tim said, also make sure to use the BC Math functions when performing arithmetic operation on floating point numbers. Specifically bcmul():
$income100 = bcmul($income, 100);
The problem with floating-point numbers is that you cannot represent decimal numbers with them (unless it can be written as a/b for integer a and b, and even then only if abs(a) < pow(2,52) and b is a power of 2).
You may be better off using string functions to get an integer value:
$tmp = explode(".",$commission);
$tmp = intval($tmp[0].str_pad(substr($tmp[1],0,2),2,"0"));
This will split up the integer part from the decimal part, ensure the decima part is two digits long, and shove it on the end of the integer part, thus effectively multiplying the original number by 100.
I think the easiest solution would be to cast it to a float with floatval()
$income = floatval($comission)
leave the rest of the code as is and it should work as intended.
I'm trying to do an echo of a variable containing 1400000.
so there is written: echo round(1400000);
this gives 1,4E+6 instead of the full number.
Anybody an idea on how to display it fully?
It seems that round was the problem.
I changed it with number_format() and this does the job just fine.
Thanks Aron and Paul for the answers.
Related to your question, I also came across this comment on the PHP website.
PHP switches from the standard decimal
notation to exponential notation for
certain "special" floats. You can see
a partial list of such "special"
values with this:
for( $tmp = 0, $i = 0; $i < 100; $i++ )
{
$tmp += 100000;
echo round($tmp),"\n";
}
So, if you add two floats, end up with
a "special" value, e.g. 1.2E+6, then
put that value unmodified into an
update query to store the value in a
decimal column, say, you will likely
get a failed transaction, since the
database will see "1.2E+6" as varchar
data, not decimal. Likewise, you will
likely get an XSD validation error if
you put the value into xml.
I have to be honest: this is one of
the strangest things I have seen in
any language in over 20 years of
coding, and it is a colossal pain to
work around.
It seems there has not been a "real" fix yet, but judging from the comments in the bug report Paul Dixon referered to earlier, his solution seems to work.
Possibly related to this bug report, so you could try
printf("%d", $myvar);
I have a small financial application with PHP as the front end and MySQL as the back end. I have ancient prejudices, and I store money values in MySQL as an integer of cents. My HTML forms allow input of dollar values, like "156.64" and I use PHP to convert that to cents and then I store the cents in the database.
I have a function that both cleans the dollar value from the form, and converts it to cents. I strip leading text, I strip trailing text, I multiply by 100 and convert to an integer. That final step is
$cents = (integer) ($dollars * 100);
This works fine for almost everything, except for a very few values like '156.64' which consistently converts to 15663 cents. Why does it do this?
If I do this:
$cents = (integer) ($dollars * 100 + 0.5);
then it consistently works. Why do I need to add that rounding value?
Also, my prejudices about storing money amounts as integers and not floating point values, is that no longer needed? Will modern float calculations produce nicely rounded and accurate money values adequate for keeping 100% accurate accounting?
If you want precision, you should store your money values using the DECIMAL data type in MySQL.
Your "prejudices" about floats will never be overcome - it's fundamental to the way they work. Without going into too much detail, they store a number based on powers of two and since not all decimal number can be presented this way, it doesn't always work. Your only reliable solution is to store the number as a sequence of digits and the location of the decimal point (as per DECIMAL type mentioned above).
I'm not 100% on the PHP, but is it possible the multiplication is converting the ints to floats and hence introducing exactly the problem you're trying to avoid?
Currency/money values should never be stored in a database (or used in a program) as floats.
Your integer method is fine, as is using a DECIMAL, NUMERIC or MONEY type where available.
Your problem is caused by $dollars being treated as a float and PHP doesn't have a better type to deal with money. Depending on when $dollars is being assigned, it could be being treated as a string or a float, but is certainly converted to a float if it's still a string for the * 100 operation if it looks like a float.
You might be better off parsing the string to an integer "money" value yourself (using a regex) instead of relying on the implicit conversions which PHP is doing.
The code you posted does the multiplication first, forcing a floating point calculation that introduces error, before converting the value to an integer. Instead, you should avoid floating point arithmetic entirely by reversing the order. Convert to integer values first, then perform the arithmetic.
Assuming previous code already validated and formatted the input, try this:
list($bills, $pennies) = explode('.', $dollars);
$cents = 100 * $bills + $pennies;
Your prejudice against floating point values to represent money is well founded because of truncation and because of values being converted from base-10 to base-2 and back again.
Casting does not round() as in round-to-nearest, it truncates at the decimal: (int)3.99 yields 3. (int)-3.99 yields -3.
Since float arithmetic often induces error (and possibly not in the direction you want), use round() if you want reliable rounding.
You should never ever store currency in floating point, because it always get results you don't expect.
Check out php BC Maths, it allow you to store your currency as string, then perform very high precision arithmetic on them.
Instead of using
$cents = (integer) ($dollars * 100);
you may want to try to use:
$cents = bcmul($dollars, 100, 2);
When converting from float to integer, the number will be rounded towards zero (src).
Read the Floating point precision warning.
There's no point in storing money as integer if you enter it through a floating point operation (no pun intended). If you want to convert from string to int and be consistent with your "prejudice" you can simply use string functions.
You can use an arbitrary precision library to divide by 10 (they handle numbers internally as strings), e.g. bcdiv() or gmp_div_q(), but of course, you could have also used it from the beginning for all the math.
Or you can use plain string functions:
<?php
// Quick ugly code not fully tested
$input = '156.64';
$output = NULL;
if( preg_match('/\d+(\.\d+)?/', $input) ){
$tmp = explode('.', $input);
switch( count($tmp) ){
case 1:
$output = $tmp[0];
break;
case 2:
$output = $tmp[0] . substr($tmp[1], 0, 2);
break;
default:
echo "Invalid decimal\n";
}
}else{
echo "Invalid number\n";
}
var_dump($output);
?>