Modulo negative floats using "%" and gmp_mod does not work - php

I try to get the result of -0.15 modulo 5 in PHP.
Following codes always return 0.
$mod = ((-0.15) % 5)
$mod = (-0.15 % 5)
$mod = gmp_mod("-0,15", "5");
$mod = gmp_mod(-0.15, 5);
When I type "-0.15 mod 5" into google, it returns: 4.85
What is wrong with the code I use in PHP?

According to http://php.net/language.operators.arithmetic, "Operands of modulus are converted to integers (by stripping the decimal part) before processing."
So $mod = 0 % 5, which would be 0.

Related

How can I calculate a really long number with modulo without using bcmod?

The bcmod function is deactivated and I won't be able to activate this because its not my own server.
For a reason I need to calculate an integer with a length of atleast 24 with modulo 97.
Integer cant be that long, thats why it can't work...
I already tried it with simple operator "%" and the "fcmod" lib but this returns me completely wrong numbers.
Does someone know if I can solve this by my own without any other libraries or do I really need "bcmod"?
This would be the code as example:
123456789101112131415171%97
The real answer would be 96 but it returns me -94
If you've got a number that is too big you can divide the problem into several steps with smaller numbers. An example:
Suppose we do this in steps of 3 digits. So, 1550 % 16 is the same as first doing 155 % 16, which is 11. After this first step we combine the result with what was left of the whole number. That is: 11 and 0 which gives 110. We are now left with only 3 digits, so we do 110 % 16 which is 14. So the result is 14.
We can implement this in a function, I use 8 digits at once, because it is quicker:
function modulo($value, $modulo)
{
while ((strlen($value) > strlen($modulo)) ||
(intval($value) >= $modulo)) {
$head = substr($value, 0, 8);
$tail = substr($value, 8);
$value = ($head % $modulo) . $tail;
}
return $value;
}
Now if we do:
$value = "123456789101112131415171";
$modulo = 97;
echo modulo($value, $modulo);
We get 96. Note how the big integer is a string, otherwise it won't work. There are a lot of implicit type conversions going on in this function.
See: PHP Sandbox.
A shorter version is possible, but is functionally the same:
function modulo($value, $modulo)
{
while ((strlen($value) > strlen($modulo)) ||
(intval($value) >= $modulo)) {
$value = (substr($value, 0, 8) % $modulo) . substr($value, 8);
}
return $value;
}
See: PHP Sandbox.

Strange Modulus Operator Result - PHP

I am working on a PHP application and mathematical operation was resulting wrong answer which was displaying wrong results. So, I started digging down and after few hours effort I was able to detect the issue.
Here is the problematic Expression:
echo -1 % 26;
The answer should be 25 but it gives -1. I don't know, is there anything wrong with my expression?
PHP Output:
Calculator:
Can anyone please identify, where is the problem?
This is the expected behaviour. From the PHP manual
The result of the modulo operator % has the same sign as the dividend — that is, the result of $a % $b will have the same sign as $a
If the sign of the dividend (the part to the left of the %) changes, the result will also change. You can find the positive equivalent of a negative remainder by adding the divisor. -1 is equivalent to 25 modulo 26 since -1 + 26 = 25.
Hence you can do the following to get the positive result:
function modulo($dividend, $divisor) {
$result = $dividend % $divisor;
return $result < 0 ? $result + $divisor : $result;
}
$calculation = modulo(-1, 26); // 25
$calculation2 = modulo(51, 26); // 25
How about ?
$ cat test.php
<?php
function truemod($num, $mod) {
return ($mod + ($num % $mod)) % $mod;
}
echo truemod(-1, 26).PHP_EOL;
?>
Output
$ php test.php
25

PHP modulus operator for doubles

I read here that:
Modulus with non integer numbers will give unpredictable results.
However, I tried to play a bit with it, and it seems to give pretty predictable results:
function mod($a, $b) {
echo "$a % $b = " . ($a % $b) . '<br>';
}
mod(10.3, 4);
mod(10.3, 2);
mod(-5.1, 3);
// OUTPUT:
// 10.3 % 4 = 2
// 10.3 % 2 = 0
// -5.1 % 3 = -2
In other words, the double seems to be converted to integer first.
Is there any definition of how % works when the first operand is double?
use:
fmod(10.3, 4)
I too had to do the same thing but I noticed doubles are converted to int and using fmod returns a double.
If this helps
From http://php.net/manual/en/language.operators.arithmetic.php
The result of the modulus operator % has the same sign as the dividend — that is, the result of $a % $b will have the same sign as $a.

PHP How do I round down to two decimal places? [duplicate]

This question already has answers here:
Truncate float numbers with PHP
(14 answers)
Closed 11 months ago.
I need to round down a decimal in PHP to two decimal places so that:
49.955
becomes...
49.95
I have tried number_format, but this just rounds the value to 49.96. I cannot use substr because the number may be smaller (such as 7.950). I've been unable to find an answer to this so far.
Any help much appreciated.
This can work: floor($number * 100) / 100
Unfortunately, none of the previous answers (including the accepted one) works for all possible inputs.
1) sprintf('%1.'.$precision.'f', $val)
Fails with a precision of 2 : 14.239 should return 14.23 (but in this case returns 14.24).
2) floatval(substr($val, 0, strpos($val, '.') + $precision + 1))
Fails with a precision of 0 : 14 should return 14 (but in this case returns 1)
3) substr($val, 0, strrpos($val, '.', 0) + (1 + $precision))
Fails with a precision of 0 : -1 should return -1 (but in this case returns '-')
4) floor($val * pow(10, $precision)) / pow(10, $precision)
Although I used this one extensively, I recently discovered a flaw in it ; it fails for some values too. With a precision of 2 : 2.05 should return 2.05 (but in this case returns 2.04 !!)
So far the only way to pass all my tests is unfortunately to use string manipulation. My solution based on rationalboss one, is :
function floorDec($val, $precision = 2) {
if ($precision < 0) { $precision = 0; }
$numPointPosition = intval(strpos($val, '.'));
if ($numPointPosition === 0) { //$val is an integer
return $val;
}
return floatval(substr($val, 0, $numPointPosition + $precision + 1));
}
This function works with positive and negative numbers, as well as any precision needed.
Here is a nice function that does the trick without using string functions:
<?php
function floorp($val, $precision)
{
$mult = pow(10, $precision); // Can be cached in lookup table
return floor($val * $mult) / $mult;
}
print floorp(49.955, 2);
?>
An other option is to subtract a fraction before rounding:
function floorp($val, $precision)
{
$half = 0.5 / pow(10, $precision); // Can be cached in a lookup table
return round($val - $half, $precision);
}
I think there is quite a simple way to achieve this:
$rounded = bcdiv($val, 1, $precision);
Here is a working example. You need BCMath installed but I think it's normally bundled with a PHP installation. :) Here is the documentation.
function roundDown($decimal, $precision)
{
$sign = $decimal > 0 ? 1 : -1;
$base = pow(10, $precision);
return floor(abs($decimal) * $base) / $base * $sign;
}
// Examples
roundDown(49.955, 2); // output: 49.95
roundDown(-3.14159, 4); // output: -3.1415
roundDown(1000.000000019, 8); // output: 1000.00000001
This function works with positive and negative decimals at any precision.
Code example here: http://codepad.org/1jzXjE5L
Multiply your input by 100, floor() it, then divide the result by 100.
You can use bcdiv PHP function.
bcdiv(49.955, 1, 2)
Try the round() function
Like this: round($num, 2, PHP_ROUND_HALF_DOWN);
For anyone in need, I've used a little trick to overcome math functions malfunctioning, like for example floor or intval(9.7*100)=969 weird.
function floor_at_decimals($amount, $precision = 2)
{
$precise = pow(10, $precision);
return floor(($amount * $precise) + 0.1) / $precise;
}
So adding little amount (that will be floored anyways) fixes the issue somehow.
Use formatted output
sprintf("%1.2f",49.955) //49.95
DEMO
You can use:
$num = 49.9555;
echo substr($num, 0, strpos($num, '.') + 3);
function floorToPrecision($val, $precision = 2) {
return floor(round($val * pow(10, $precision), $precision)) / pow(10, $precision);
}
An alternative solution using regex which should work for all positive or negative numbers, whole or with decimals:
if (preg_match('/^-?(\d+\.?\d{1,2})\d*$/', $originalValue, $matches)){
$roundedValue = $matches[1];
} else {
throw new \Exception('Cannot round down properly '.$originalValue.' to two decimal places');
}
Based on #huysentruitw and #Alex answer, I came up with following function that should do the trick.
It pass all tests given in Alex's answer (as why this is not possible) and build upon huysentruitw's answer.
function trim_number($number, $decimalPlaces) {
$delta = (0 <=> $number) * (0.5 / pow(10, $decimalPlaces));
$result = round($number + $delta, $decimalPlaces);
return $result ?: 0; // get rid of negative zero
}
The key is to add or subtract delta based on original number sign, to support trimming also negative numbers.
Last thing is to get rid of negative zeros (-0) as that can be unwanted behaviour.
Link to "test" playground.
EDIT: bcdiv seems to be the way to go.
// round afterwards to cast 0.00 to 0
// set $divider to 1 when no division is required
round(bcdiv($number, $divider, $decimalPlaces), $decimalPlaces);
sprintf("%1.2f",49.955) //49.95
if you need to truncate decimals without rounding - this is not suitable, because it will work correctly until 49.955 at the end, if number is more eg 49.957 it will round to 49.96
It seems for me that Lght`s answer with floor is most universal.
Did you try round($val,2) ?
More information about the round() function

Dividing with a remainder in PHP

I have a part in my code where I need to divide and have a remainder instead of a decimal answer.
How can I do this?
$quotient = intval($dividend / $divisor);
$remainder = $dividend % $divisor;
Using intval instead of floor will round the quotient towards zero, providing accurate results when the dividend is negative.
You can do what you are describing using the "%" (modulus) operator. The following code is an example of dividing with a remainder.
$remainder=$num % $divideby;
$number=explode('.',($num / $divideby));
$answer=$number[0];
echo $answer.' remainder '.$remainder;
A solution for positive and negative numbers:
$quotient = $dividend / $divison;
$integer = (int) ($quotient < 0 ? ceil($quotient) : floor($quotient));
$remainder = $dividend % $divisor;
The mathematical correct answer is:
remainder = dividend % divisor;
quotient = (dividend - remainder) / divisor;
and the remainder verifies the condition 0 <= remainder < abs(divisor).
Unfortunately, many programming languages (including PHP) don't handle the negative numbers correctly from the mathematical point of view. They use different rules to compute the value and the sign of the remainder. The code above does not produce the correct results in PHP.
If you need to work with negative numbers and get the mathematical correct results using PHP then you can use the following formulae:
$remainder = (($dividend % $divider) + abs($divider)) % abs($divider);
$quotient = ($dividend - $remainder) / $divider;
They rely on the way PHP computes modulus with negative operands and they may not provide the correct result if they are ported to a different language.
Here is a script that implements these formulae and checks the results against the values provided as example in the aforementioned mathematical correct answer.
If you need to look it up, the % operator is called mod (or modulus).
I had to develop this approach because my numerator was a float value and modulus was rounding results.
Using Raffaello's approach offered here for dividing floats and taking from Sam152's solution above came up with the following.
$a = 2.1;
$b = 8;
$fraction = $a / (float) $b;
$parts = explode('.', $fraction);
$int = $parts[0];
$remainder = $score - ($int*$b) ;
Use This Function Its an array
Description
array gmp_div_qr ( resource $n , resource $d [, int $round ] )
The function divides n by d .
reference : http://php.net/manual/en/function.gmp-div-qr.php
An example to show strings like 1 hour 6 minutes using floor() and modulus (%) if only minutes/seconds given:
$minutes=126;
if($minutes < 60) {
$span= $minutes.' min.';
} else {
$rem=$minutes % 60;
$span=floor($minutes/60).' h. '. (($rem>0) ? $rem.' min.':'');
}
// echo 'Hello Jon Doe, we notify you that even will last for 2 h. 6 min.
echo 'Hello Jon Doe, we notify you that event will last for '.$span;
It seems to be an old post, but for those who might be interested here is a very light package that could meet your needs: https://github.com/romainnorberg/residue (feedbacks are welcome)

Categories