I want to round a number and I need a proper integer because I want to use it as an array key. The first "solution" that comes to mind is:
$key = (int)round($number)
However, I am unsure if this will always work. As far as I know (int) just truncates any decimals and since round($number) returns a float with theoretically limited precision, is it possible that round($number) returns something like 7.999999... and then $key is 7 instead of 8?
If this problem actually exists (I don't know how to test for it), how can it be solved? Maybe:
$key = (int)(round($number) + 0.0000000000000000001) // number of zeros chosen arbitrarily
Is there a better solution than this?
To round floats properly, you can use:
ceil($number): round up
round($number, 0): round to the nearest integer
floor($number): round down
Those functions return float, but from Niet the Dark Absol comment: "Integers stored within floats are always accurate, up to around 2^51, which is much more than can be stored in an int anyway."
round(), without a precision set always rounds to the nearest whole number. By default, round rounds to zero decimal places.
So:
$int = 8.998988776636;
round($int) //Will always be 9
$int = 8.344473773737377474;
round($int) //will always be 8
So, if your goal is to use this as a key for an array, this should be fine.
You can, of course, use modes and precision to specify exactly how you want round() to behave. See this.
UPDATE
You might actually be more interested in intval:
echo intval(round(4.7)); //returns int 5
echo intval(round(4.3)); // returns int 4
What about simply adding 1/2 before casting to an int?
eg:
$int = (int) ($float + 0.5);
This should give a predictable result.
Integers stored within floats are always accurate, up to around 253, which is much more than can be stored in an int anyway. I am worrying over nothing.
For My Case, I have to make whole number by float or decimal type
number. By these way i solved my problem. Hope It works For You.
$value1 = "46.2";
$value2 = "46.8";
// If we print by round()
echo round( $value1 ); //return float 46.0
echo round( $value2 ); //return float 47.0
// To Get the integer value
echo intval(round( $value1 )); // return int 46
echo intval(round( $value2 )); // return int 47
My solution:
function money_round(float $val, int $precision = 0): float|int
{
$pow = pow(10, $precision);
$result = (float)(intval((string)($val * $pow)) / $pow);
if (str_contains((string)$result, '.')) {
return (float)(intval((string)($val * $pow)) / $pow);
}
else {
return (int)(intval((string)($val * $pow)) / $pow);
}
}
Round to the nearest integer
$key = round($number, 0);
Related
I'm trying to multiply some small numbers in PHP, but bcmul is returning zero because the float value is being turned into scientific notation.
I tried using sprintf('%.32f',$value) on the small float values, but since the number of decimal places is unknown, it gets the wrong rounding, and then it'll cause rounding errors when multiplying.
Also, I can't use strpos('e',$value) to find out if it's scientific notation number, because it doesn't finds it even if I cast it as a string with (string)$value
Here's some example code:
$value = (float)'7.4e-5'; // This number comes from an API like this
$value2 = (float)3.65; // Another number from API
echo bcmul($value,$value2); // 0
By default the bc-functions round to 0 decimals. You can change this behavior by either using bcscale or by by changing the bcmath.scale value in your php.ini.
Okay, I found a way to solve it, so, here's how to multiply very small floating point numbers without needing to set an explicit scale for the numbers:
function getDecimalPlaces($value) {
// first we get how many decimal places the small number has
// this code was gotten on another StackOverflow answer
$current = $value - floor($value);
for ($decimals = 0; ceil($current); $decimals++) {
$current = ($value * pow(10, $decimals + 1)) - floor($value * pow(10, $decimals + 1));
}
return $decimals;
}
function multiplySmallNumbers($value, $smallvalue) {
$decimals = getDecimalPlaces($smallvalue); // Then we get number of decimals on it
$smallvalue = sprintf('%.'.$decimals.'f',$smallvalue ); // Since bcmul uses the float values as strings, we get the number as a string with the correct number of zeroes
return (bcmul($value,$smallvalue));
}
I am trying to do a 2 digit precision in PHP Laravel project but it doesnt work. I have the value 1234666.6666667 that I want to make 1234666.66 but all the results I've seen in here or/and in other search pages.
This is my code:
$value = 1234666.6666667;
return round($value,2);
any other solution?
EDIT:
As I see, you actually want to floor number to 2 decimal points, not to round it, so this answer could help you:
$value = 1234666.6666667;
floor($value * 100) / 100; // returns 1234666.66
If you want 3 decimal points you need to multiple and divide with 1000, for 4 - with 10000 and etc.
You can use number_format, it convert value to string though, so you lose real float value:
$value = 1234666.6666667;
echo number_format($value, 2, '.', ''); // prints 1234666.67
Use this function.
function truncate($i) {
return floor($i*100) / 100.0;
}
Then you can do
$value = truncate(123.5666666); // 123.56
A pragmatic way is to use round($value - 0.05, 2), but even that gets you into hot water with some edge cases. Floating point numbers just don't round well. It's life I'm afraid. The closest double to 1234666.66 is
1234666.65999999991618096828460693359375
That's what $value will be after applying my formula! Really, if you want exact decimal precision, then you need to use a decimal type. Else use integer types and work in multiples of 100.
For the former choice, see http://de2.php.net/manual/en/ref.bc.php
$value = bcadd($value, 0, 2); // 1234666.6666667 -> 1234666.66
Another more exotic way to solve this issue is to use bcadd() with a dummy value for the $right_operand of 0,
This will give you 2 number after decimal.
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 know of the PHP function floor() but that doesn't work how I want it to in negative numbers.
This is how floor works
floor( 1234.567); // 1234
floor(-1234.567); // -1235
This is what I WANT
truncate( 1234.567); // 1234
truncate(-1234.567); // -1234
Is there a PHP function that will return -1234?
I know I could do this but I'm hoping for a single built-in function
$num = -1234.567;
echo $num >= 0 ? floor($num) : ceil($num);
Yes intval
intval(1234.567);
intval(-1234.567);
Truncate floats with specific precision:
echo bcdiv(2.56789, 1, 1); // 2.5
echo bcdiv(2.56789, 1, 3); // 2.567
echo bcdiv(-2.56789, 1, 1); // -2.5
echo bcdiv(-2.56789, 1, 3); // -2.567
This method solve the problem with round() function.
Also you can use typecasting (no need to use functions),
(int) 1234.567; // 1234
(int) -1234.567; // -1234
http://php.net/manual/en/language.types.type-juggling.php
You can see the difference between intval and (int) typecasting from here.
another hack is using prefix ~~ :
echo ~~1234.567; // 1234
echo ~~-1234.567; // 1234
it's simpler and faster
Tilde ~ is bitwise NOT operator in PHP and Javascript
Double tilde(~) is a quick way to cast variable as integer, where it is called 'two tildes' to indicate a form of double negation.
It removes everything after the decimal point because the bitwise operators implicitly convert their operands to signed 32-bit integers. This works whether the operands are (floating-point) numbers or strings, and the result is a number
reference:
https://en.wikipedia.org/wiki/Double_tilde
What does ~~ ("double tilde") do in Javascript?
you can use intval(number); but if your number bigger than 2147483648 (and your machine/os is x64) all bigs will be truncated to 2147483648. So you can use
if($number < 0 )
$res = round($number);
else
$res = floor($number);
echo $res;
You can shift the decimal to the desired place, intval, and shift back:
function truncate($number, $precision = 0) {
// warning: precision is limited by the size of the int type
$shift = pow(10, $precision);
return intval($number * $shift)/$shift;
}
Note the warning about size of int -- this is because $number is potentially being multiplied by a large number ($shift) which could make the resulting number too large to be stored as an integer type. Possibly converting to floating point might be better.
You could get fancy with a $base parameter, and sending that to intval(...).
Could (should) also get fancy with error/bounds checking.
An alternative approach would be to treat number as a string, find the decimal point and do a substring at the appropriate place after the decimal based on the desired precision. Relatively speaking, that won't be fast.
See, I want to write a function that takes a float number parameter and rounds the float to the nearest currency value (a float with two decimal places) but if the float parameter has a zero fraction (that is, all zeroes behind the decimal place) then it returns the float as an integer (or i.e. truncates the decimal part since they're all zeroes anyways.).
However, I'm finding that I can't figure out how to determine if if a fraction has a zero fraction. I don't know if there's a PHP function that already does this. I've looked. The best I can think of is to convert the float number into an integer by casting it first and then subtract the integer part from the float and then check if the difference equals to zero or not.
if($value == round($value))
{
//no decimal, go ahead and truncate.
}
This example compares the value to itself, rounded to 0 decimal places. If the value rounded is the same as the value, you've got no decimal fraction. Plain and simple.
A little trick with PHPs type juggling abilities
if ($a == (int) $a) {
// $a has a zero fraction value
}
I think the best way:
if ((string)$value == (int)$value){
...
}
Example:
$value = 2.22 * 100;
var_dump($value == (int)$value); // false - WRONG!
var_dump($value == round($value)); // false - WRONG!
var_dump((string)$value == (int)$value); // true - OK!
function whatyouneed($number) {
$decimals = 2;
printf("%.".($number == (int)($number) ? '0' : $decimals)."F", $number);
}
So basically it's either printf("%.2F") if you want 2 decimals and printf("%.2F") if you want none.
Well, the problem is that floats aren't exact. Read here if you're interested in finding out why. What I would do is decide on a level of accuracy, for example, 3 decimal places, and base exactness on that. To do that, you multiply it by 1000, cast it to an int, and then check if $your_number % 1000==0.
$mynumber = round($mynumber *1000);
if ($mynumber % 1000==0)
{ isInt() }
Just so you know, you don't have to write a function to do that, there's already one that exists:
$roundedFloat = (float)number_format("1234.1264", 2, ".", ""); // 1234.13
If you want to keep the trailing .00, just omit the float cast (although it will return a string):
$roundedFloatStr = number_format("1234.000", 2, ".", ""); // 1234.00