PHP: strings automatically converted to float and gives negative numbers - php

I have a PHP code that will compute the balance of the quantity but it gives me a negative value as a balance quantity as shown in the image below.
I tried to check the quantities if what's causing the problem and try to var_dump the quantity. after checking using var_dump, it shows that the data type of my quantity is string while my balance quantity is float.
so far, I have my code below:
$query_po_quantity = mysqli_query($new_conn, "SELECT quantity, po_number FROM purchase_order WHERE supplier_name = '$supplier_name' AND category_name = '$category_name' AND activity = '$activity' AND description = '$description'");
$row = mysqli_fetch_assoc($query_po_quantity);
$po_quantity = $row['quantity'];
$po_number = $row['po_number'];
$query_rr_quantity = mysqli_query($new_conn, "SELECT SUM(total_received) AS quantity FROM receiving_reports WHERE po_number = '$po_number' AND category_name = '$category_name' AND activity = '$activity' AND description = '$description'");
$row = mysqli_fetch_assoc($query_rr_quantity);
$rr_quantity = $row['quantity'];
$balance = $po_quantity - $rr_quantity;
$supplier_name = preg_replace('/\\\\/', '', $supplier_name);
echo $po_quantity.' - '.$rr_quantity.' = '.$balance.'<br />';
This is the output:
how can I get the actual balance?

The reason you're getting an incorrect result when calculating 0.42 - 0.420000000000000000004 is due to errors with floating point precision. This is due to the way floating point numbers are stored, and both MySQL and PHP are susceptible to floating point errors if done incorrectly, but they also both have ways to prevent them when you do need highly precise calculations. With floating point types only the approximate value is stored and attempts to treat them as exact values in comparisons may lead to problems.
For PHP, this means you need to use either the arbitrary precision math functions or gmp functions. For MySQL, you need to be storing the numbers using the DECIMAL format with the desired precision you require.
First thing's first, you need to change the data type of your column in MySQL to DECIMAL, not a string. Strings are inappropriate to store numbers. Even if you were using a FLOAT or DOUBLE to store your values
your code may have actually worked, because these values likely would have been rounded.
Next, seeing as the value 0.420000000000000000004 came from a string stored in your database, I'm assuming the error stems from whatever calculations you did using PHP beforehand when you were calculating the value to be inserted. You will need to update this code to use precise math.

Use number_format:
$rr_quantity = number_format($row['quantity'], 2);

Float variable range 1.7E-308 and 1.7E+308 so it's give 15 digits of accuracy. Use number format

Related

MySQL Decimal 9.99999999

I am getting the currency from google finance using a script and then I am writing the data into a database.
However when I do, I get 9.99999999 instead of what I sent over. I have my InnoDB set to DECIMAL (9,8).
$conn->set_charset('utf8');
$add_currency_query = "INSERT INTO `currency_table`
(`currency_rate`, `time_fetched`, `service`)
VALUES ('$converted_amount', UTC_TIMESTAMP(), 'google-finance')";
And my PHP
$get = explode("<span class=bld>",$get);
$get = explode("</span>",$get[1]);
$converted_amount = preg_replace('/[^0-9\.]/', null, $get[0]);
Any tips on how to fix this/am I doing something wrong?
DECIMAL (9,8) means 9 digits in total and 8 of that after the decimal point.
So what is the max number of that decimal? it is 9.99999999. You get that number when the one you sent is bigger than it is possible to store. MySQL just stores as high as possible when the value overflows.
DECIMAL (9,8) means you have 9 symbols in total, 8 of those are after the dot. This means you can store only numbers up to 9.99999999 if you save anything above it it probably saves as 9.99999999
Suggestion: change your field to be something like DECIMAL (20,8)

Can't insert decimal value with PDO

I've been trawling the web for hours now and trying different methods, and I can't work out why PDO can't insert any row where one of the values contains a decimal.
For example, if the value entered into the cost field has no decimal value then it works fine. But anything like with a decimal and it just ignores the whole row.
200 works, even 200.00 works. But things like 39.99 don't.
Here's the code:
$invoice_id = $db->lastInsertId('id');
$item_name = $_POST['item_name'];
$item_qty = $_POST['item_qty'];
$item_cost = $_POST['item_cost'];
$item_vat = $_POST['item_vat'];
for($i = 0; $i < count($item_name); $i++) {
$item_query = $db->prepare("INSERT INTO hm_invoice_items(invoice, item, qty, amount, vat) VALUES(:invoice, :item, :qty, :amount, :vat)");
$item_query->bindParam(":invoice", $invoice_id);
$item_query->bindParam(":item", $item_name[$i]);
$item_query->bindParam(":qty", $item_qty[$i]);
$item_query->bindParam(":amount", $item_cost[$i]);
$item_query->bindParam(":vat", $item_vat[$i]);
if (!$item_query->execute())
{
die(showMessage("There has been a problem adding the invoice items.", "Error!"));
}
}
A var_dump tells me that the insert query is receiving the values, but it does not like dealing with decimals.
There could be an issue with decimal separator.
When debugging such cases it's essential to var_dump() e-ve-ry-thing!
Why don't you var_dump your values for the closer inspection?
Why didn't you play with decimals only, without POST, without other values?
A question titled "Can't insert decimal value with PDO" should contain short reproduceable code with decimal value present to readers and the result.
Judging by indirect measures will do no help for you and - especially - won't bring you help from strangers.
"var_dump your values" means every suspicious value, like
var_dump($item_cost[$i]);
inside your loop
if you get no output - then there is empty value, so, no wonder nothing inserted.
By the way, you're binding apparently decimal item_cost value to apparently integer amount field. Is it a typo?
But again - where is a certain reproduceable proofcode contains one insert query, one hardcoded decimal value and one result? Ugh - and table definition of course.
Try this?
$item_query->bindParam(":amount", floatval($item_cost[$i]));
At least it works for me when I deal with MySQL decimal data type with PDO.
Use the following to display the content of all the values POSTed to your PHP script:
print_r($_POST);

updating a large number in MySQL larger than 100 trillion with PHP is unreliable

When I send a value to MySQL in PHP like this:
$mysqli->query("update bank set cash = $cash");
It works fine for smaller numbers, but anything 100 trillion or larger yields unexpected results. Sometimes it updates the number in increments of 100, and sometimes not at all.
A prepared statement also has different, but unreliable results once the number gets larger than a couple billion:
$stmt->prepare("update bank set cash = ?");
$stmt->bind_param('i',$new_cash_amt);
$stmt->execute();
Use double quotes.
use or die(mysql_error()); to see you bug.
Stop using mysql* function, will be deprecated soon.
Fix:
$amount = 17;
$mysqli->query("
update player_stats
set cash = cash + $amount
where username = 'cheater2'
") or die(mysql_error());
You're using single quotes, which wont parse a php variable. It's looking for cash=cash+$amount as a string, not a variable holding data.
I'm answering my own question here.
It turns out that when you pass values like this:
$huge_number = 100000000000012345;
echo "The huge_number is: $huge_number";
It will print the following:
The huge_number is: 1.0000000000001E+17
The precise value is lost in this conversion. That is why the value increments in multiples of 100 sometimes, and not at all at other times.
As with the prepared statement, any values larger than a 32bit integer (since I put an 'i' as the type in the bound parameter) will get truncated and altered unexpectedly. I should have passed the new value as a 'd', like so:
$stmt->bind_param('d',$new_cash_amt); //This works correctly

Number format column type & calculate in PHP

I would like to insert this type of number format in to my database.
$value = "20.000,00";
I tried with FLOAT and DOUBLE, but they can't handle this. Only option left that I know which works is VARCHAR?
Although if I do this when I am working with the numbers later and tries to subtract number from each other:
$value2 = "15.933,50";
$calc = $value - $value2;
$calc is now 4.067, it should be 4.066,50 - how can this be correct?
For financial numbers, you should use the DECIMAL type. It has a fixed precision and isn't subject to the rounding problems of floating point numbers.
Never store a money number in a VARCHAR or a FLOAT.
If you want to introduce in the database your $value, you must parse it so that you can introduce the number :
$fmt = new NumberFormatter( 'da_DK', NumberFormatter::DECIMAL );
$num = $fmt->parse($value, NumberFormatter::TYPE_INT32)
To display a number you got from your DB as "20.000,00", you may use
$display_value = $fmt->format($num);
EDIT :
If you can't use a NumberFormatter, you may use this to build a string that you can introduce in a DECIMAL field (in a float one too but don't) :
$v = str_replace(',', '.', str_replace('.', '', $value));
This changes "20.000,00" to "20000.00" which the database can understand.
But it's always dangerous to ask a database to parse the strings as numbers (you may change the locale later). I'd recommend you to parse the number in PHP and to explicitly specify the locale.

float not working in mysql database

i am using $_GET['var'] to get a variable then compare it with a variable in my database. the variable is 1.1 the var is set to "float" on the database so i know it can handle decimals but when i compare them with the code below i get nothing.
include 'connect.php';
$sql=mysql_query("SELECT * FROM table WHERE stuff='$stuff'");
while ($row=mysql_fetch_assoc($sql)) {
$start=$row['start'];
}
echo $start; //nothing happens
From what I know float type isn't precise. It doesn't show you that actual value so 1.1 that you saved may not be the actual value stored. Trying setting your field as decimal and give it a length of say, 10,1 where 10 is the maximum number of digits (the precision) and 1 is the number of digits to the right of the decimal point (the scale). It should work doing query like stuff='1.1' or stuff=1.1.
WHERE stuff = '$stuff' is a String comparison.
Compare number like so
WHERE stuff = $stuff
Don't use float( even if you insert 1.1 into the table, the actual value for float type is not 1.1, but something like 1.100000023841858) . Change it to double in database (or decimal)
You might not be seeing any output because your echo is outside the loop.
The scope of your variable $start would be confined to the loop.
Change the stuff field to DOUBLE type.
Then,
SELECT * FROM table WHERE stuff=$stuff
this should be the sql query

Categories