This is quite a simple problem, but I don't see a simple and straight forward solution.
I have values that represent numeric values, but are strings. Examples: 0.0, 1.0, 10.0, 1.1.
Most time they represent integers, but there can be fractions.
I want to display these numbers as 0, 1, 10, 1.1.
I thought of these straight forward solutions, but they do not account for the occasional fractions:
$val = (int) val;
--OR--
$val = sprintf('%d', $val);
Obviously there would be long solutions, that test if the number is an integer before formatting, but I'm looking for something simple, as short as possible.
Use this simple trick:
echo 0.0 + 0;
echo 1.0 + 0;
echo 10.0 + 0;
echo 1.1 + 0;
this is equivalent to casting to float with
(float)$num
or
floatval($num)
You could try this:
$val = preg_match("/\.0$/", $number_string) ? (int)$number_string : (float)$number_string;
It uses a regular expression on the original string to match a .0 ending, and if there is a match, type casts the string value to an integer, otherwise casts the value to a float.
Related
I have got the following code:
$strNumber = "4.0";
$float = 4.0;
I am aiming to print the sum the two variables above and get 8.0 but weirdly when converting $strNumber to a float, it prints 4. The same holds true to $float - when vardumping it prints 4. As result, I have in the end 8, instead. I researched for hours for a solution but I was not successful.
I guess I could do print_r((float)$strNumber + $float . ".0"; , though, those variables will change and so it will give me an unwanted outcome. Is there actually a solution? I would very grateful if someone could help me.
Your sum is not, in fact, becoming a whole number. It is only being displayed that way. PHP has very flexible and intuitive type-casting. By putting (float) in front of the string, you can cast it to that type.
$strNumber = "4.0";
$floatNumber = (float)$strNumber;
$float = 4.0;
$sum = $floatNumber + $float;
print_r(number_format($sum, 1, '.', ','));
However, this is not necessary at all as the casting is so automatic in PHP that the following is the same thing:
$strNumber = "4.0";
$float = 4.0;
$sum = $strNumber + $float;
print_r(number_format($sum, 1, '.', ','));
Bottom line, even if you type-cast "4.0" to (float), it's still going print "4" because that's a matter of how it prints, not the data type. Use number_format() to make it look the way you want.
See here for more: https://www.php.net/manual/en/language.types.type-juggling.php
I have to validate if a float number has maximum two digits.
I've tried a lot of methods but all fails in more or lase cases.
Last of them were:
//fails for 2638655.99
private function hasMoreThanTwoDecimals(string $number): bool
{
$number = abs($number);
$intPart = floor($number);
$floatPart = $number - $intPart;
return (strlen($floatPart) > 4);
}
OR
//fails for 36.62
private function hasMoreThanTwoDecimals(string $number): bool
{
return $number * 100 - floor($number * 100) > 0.00001;
}
What other methods do you use?
You can't determine the exact number of decimals with the float datatype, because the internal representation is binary. In binary, fx. 0.1 can not be represented exactly. That's why loops always should have integer increments.
for ($i = -1; $i < 1; $i += 0.1) {
if ($i == 0) {
echo "Zero is here!";
}
}
will never say "Zero is here!" because of binary rounding issues.
Using an Epsilon
You already tried to use an epsilon (a very small value) for thesholding (here a refactored version of your function):
private function hasMoreThanTwoDecimals(string $number): bool
{
$epsilon = 0.00001;
return fmod($number * 100, 1.0) > $epsilon;
}
but fails for some values. In that case, you need to increase your epsilon value.
String Arithmetic
The more precise way is to avoid float and use string representations instead. This is your best option, since - according to your function signature - your numbers are represented as strings already.
private function hasMoreThanTwoDecimals(string $number): bool
{
return bcmod(bcmul($number, '100'), '1.0') != 0;
}
This needs the BCMath module to be included in your PHP. A package supporting BCMath and other solutions is brick/math.
The Cheap Solution
However, if you really just need to probe the number and not are doing calculations, you can get the desired result with pattern matching using preg_match.
private function hasMoreThanTwoDecimals(string $number): bool
{
// Trailing 0 does not add to number of decimals
$number = rtrim($number, '0');
return preg_match('~\.\d\d\d~', $number);
}
You can explode the number using the . delimeter, then you return the length of the second part :
$num = 2638655.99;
echo strlen(explode('.',$num)[1]); // Echo 2
Taking the question literally, if a binary floating point number has a maximum of two decimal digits after the decimal point, the fractional part must be one of .0, .25, .5, or .75.
All other binary floating point numbers really have more decimal digits, although printout formatting may hide them. For example, the closest IEEE 754 64-bit binary number to 2638655.99 is 2638655.99000000022351741790771484375, which has more than two digits after the decimal point.
You could subtract the integer part and then test for the remainder being one of the four possibilities.
Alternatively, the real question may be how to determine whether displaying the number will show no more than two digits after the decimal point. If so, convert to string using the appropriate method, then locate the decimal point and count the digits after it, for example as suggested in this answer.
$res = preg_match("^[+-]?([0]{1}|[1-9]{1}[0-9]*)(\.?[0-9]{1,2})?$", $num) == true;
would be the best solution in my opinion. You can use signs (optional) and enforce that a number starts with only one zero.
Possible:
+0.10
+123.01
-1
123
Not possible:
00.0
0001.0
1.
123.123
Be aware that preg_match returns 0 if no match is found and false if an error occurred (preg_match)
you can use the number_format
number_format($number, 2, '.', '');
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.
I need to do this rather strange thing, let's say i have:
$number = rand(1, 9);
(This is just an example of what number it could be, in reality i get it in entirely different way)
And now i need "convert" that number to 0.2 or whatever number i got, basically it has to begin with 0 and be a float type of number.
PHP does not support explicit type casting in variable declaration. To convert the int to a float in the way you want to simply divide by 10:
$number = rand(1, 9) / 10;
See this page on PHP Type Juggling for more info. If you mix floats and ints or other types they will be re-casted. Exmple:
echo 10 + 2.5; // gives you 12.5, a float because of the types used
Edit: PHP does have explicit type casting, just not in variable declaration. But even if you cast an integer as a float, it won't display with a decimal place. To do that use PHP's number_format function instead:
echo number_format(10, 1); // gives you 10.0
Edit 2: If you simply want to make your number a decimal between 0 and 1 (such that 2 becomes 0.2, 25 becomes 0.25, etc.) you could use the following function:
function getNumAsDecimal($num) {
return ($num / pow(10, strlen((string)$num)));
}
So getNumAsDecimal(2) would return 0.2.
function Floatize(){
return (float) (rand(1, 9) / 10);
}
echo Floatize(); // will return something like 0.2 or 0.5 or 0.9
$number=(float)rand(1, 9)/10;
See PHP type casting.
How can I separate a number and get the first two digits in PHP?
For example: 1345 -> I want this output=> 13 or 1542 I want 15.
one possibility would be to use substr:
echo substr($mynumber, 0, 2);
EDIT:
please not that, like hakre said, this will break for negative numbers or small numbers with decimal places. his solution is the better one, as he's doing some checks to avoid this.
First of all you need to normalize your number, because not all numbers in PHP consist of digits only. You might be looking for an integer number:
$number = (int) $number;
Problems you can run in here is the range of integer numbers in PHP or rounding issues, see Integers Docs, INF comes to mind as well.
As the number now is an integer, you can use it in string context and extract the first two characters which will be the first two digits if the number is not negative. If the number is negative, the sign needs to be preserved:
$twoDigits = substr($number, 0, $number < 0 ? 3 : 2);
See the Demo.
Shouldn't be too hard? A simple substring should do the trick (you can treat numbers as strings in a loosely typed language like PHP).
See the PHP manual page for the substr() function.
Something like this:
$output = substr($input, 0, 2); //get first two characters (digits)
You can get the string value of your number then get the part you want using
substr.
this should do what you want
$length = 2;
$newstr = substr($string, $lenght);
With strong type-hinting in new version of PHP (> PHP 7.3) you can't use substr on a function if you have integer or float. Yes, you can cast as string but it's not a good solution.
You can divide by some ten factor and recast to int.
$number = 1345;
$mynumber = (int)($number/100);
echo $mynumber;
Display: 13
If you don't want to use substr you can divide your number by 10 until it has 2 digits:
<?php
function foo($i) {
$i = abs((int)$i);
while ($i > 99)
$i = $i / 10;
return $i;
}
will give you first two digits