Why does the modulus operator behave differently in Perl and PHP? - php

I've this PHP function which does not work for negative numbers:
function isOdd($num)
{
return $num % 2 == 1;
}
but it works for positive number.
I have this Perl routine which does the exact same thing and works for negative number also
sub isOdd()
{
my ($num) = #_;
return $num % 2 == 1;
}
Did I make any mistake in translating the function ? or is it PHP bug ?

In PHP the sign of the result of x % y is the sign of dividend which is x but
in Perl it is the sign of the divisor which is y.
So in PHP the result of $num % 2 can be be either 1, -1 or 0.
So fix your function compare the result with 0:
function isOdd($num) {
return $num % 2 != 0;
}

Related

Algorithm to find positive and negative integer square roots (without given boundaries)

I've been practicing a lot of algorithms recently for an interview. I was wondering if there was another way to solve this problem. I wrote it in a way where I only increment it positively, because I know from basic math that two negatives multiplied by each other would result to a positive number, so I would just have to make the integer that would satisfy the condition to negative.
Is there a way to write this elegantly where you didn't have the knowledge of multiplying two negative numbers result to a positive?
<?php
# Z = {integers}
# B = {x:x, x is an element of Z, x^2 + 1 = 10}
$numNotFound = true;
$x = 0;
$b = [];
while ($numNotFound) {
if ($x*$x + 1 == 10) {
array_push($b, $x, $x*-1);
$numNotFound = false;
}
$x++;
}
echo json_encode($b); #[3, -3]
Updated
This solution does not use the fact that -1 * -1 = 1. It will output the first number found as the first element in the array. If x=-3 then [-3,3] or if x=3 [3,-3].
$numNotFound = TRUE;
$x = 0;
$b = [];
Do{
if ((pow($x, 2) + 1) === 10) {
array_push($b, $x, 0 - $x);
$numNotFound = FALSE;
}
$x++;
}while($numNotFound);
echo json_encode($b); //[3, -3]

Format number to N significant digits in PHP

I would like to format (round) float (double) numbers to lets say 2 significant digits for example like this:
1 => 1
11 => 11
111 => 110
119 => 120
0.11 => 0.11
0.00011 => 0.00011
0.000111 => 0.00011
So the arbitrary precision remains same
I expect there is some nice function for it already built in, but could not find any so far
I was pointed to How to round down to the nearest significant figure in php, which is close but doesn't work for N significant digits and I'm not sure what it does with 0.000XXX numbers
To get a number rounded to n significant figures you need to find the size of the number in powers of ten, and subtract that from n.
This works fine for simple rounding:
function sigFig($value, $digits)
{
if ($value == 0) {
$decimalPlaces = $digits - 1;
} elseif ($value < 0) {
$decimalPlaces = $digits - floor(log10($value * -1)) - 1;
} else {
$decimalPlaces = $digits - floor(log10($value)) - 1;
}
$answer = round($value, $decimalPlaces);
return $answer;
}
This will give the following:
0.0001234567 returns 0.0001235
123456.7 returns 123500
However a value such as 10 to four significant figures should strictly be represented as 10.00 to signify the precision to which the value is known.
If this is the desired output you can use the following:
function sigFig($value, $digits)
{
if ($value == 0) {
$decimalPlaces = $digits - 1;
} elseif ($value < 0) {
$decimalPlaces = $digits - floor(log10($value * -1)) - 1;
} else {
$decimalPlaces = $digits - floor(log10($value)) - 1;
}
$answer = ($decimalPlaces > 0) ?
number_format($value, $decimalPlaces) : round($value, $decimalPlaces);
return $answer;
}
Now 1 is displayed as 1.000
With little modification to possible duplicate, answer by Todd Chaffee:
public static function roundRate($rate, $digits)
{
$mod = pow(10, intval(round(log10($rate))));
$mod = $mod / pow(10, $digits);
$answer = ((int)($rate / $mod)) * $mod;
return $answer;
}
To make sigFig(0.9995, 3) output 1.00, use
if(floor(log10($value)) !== floor(log10(round($value, $decimalPlaces)))) {$decimalPlaces--;}
Said line of code should be placed before declaring $answer.
If input $value is negative, set a flag and remove the sign at the beginning of the function, like this:
if($value < 0){$flag = 1;}
$value = ltrim($value, "-");
Then right before returning $answer, detect if the flag is set and if so restore the negative sign, like this:
if(isset($flag)){$answer = "-".$answer;}
Finally, for result values with ambiguous number of significant digits (e.g., 1000, 12000,...), express the result in scientific notation to the desired number of significant digits using sprintf or printf.

Is this expression a PHP bug? 6227020800 % 10 = 4

Writing some code connected with factorials (counting sum of numbers of factorial) I noticed that 13! modulus 10 equals 4.
function fact($n)
{
if ($n == 0) return 1;
return $n * fact($n-1);
}
function sum_num($n)
{
$sum = 0;
while ($n > 0)
{
$sum = $sum + ($n % 10);
$n = floor($n/10);
}
return $sum;
}
$n = 13;
$buff = fact($n);
echo $n."! = ".$buff;
echo "<br>";
echo "Summ ".$n."! = ".sum_num($buff);
Output is:
13! = 6227020800
Summ 13! = 31
But Summ should be 27. I begun search and found that on the first step I am getting 4 instead 0.
6227020800 % 10 = 4
And I don't understand why?
6227020800 requires 33 bits. The most siginficant bit gets truncated and you get you the number 1932053504 (modulo 10 of which is 4).
For arbitrary precision math use bc* functions, e.g. bcmod(6227020800, 10).
May be you should use bcmath php module instead for this operations.
http://php.net/manual/en/book.bc.php
Just take care that this module uses strings as inputs.
I'm pretty sure, you use a 32-bit version. Here the max value is 4.294.967.296.

PHP: Big integer base 10 represented as string to binary string

I need to convert a really big integer that is represented as a string to a binary string (aka normal integer, but it is always bigger as normal php integer can hold) to efficiently store it in database and have a unique index on it.
The number comes from GMP (gmp_strval()) and may have different lengths, usually about 200-300 "characters" in it, so it never fits into PHP integer. The idea is to convert it into a binary string representing an integer, kind of big integer. Can I do it with PHP?
Sure you can do this.
Remember how to convert a decimal number to binary by hand.
look if the last digit is even (gives a 0) or odd (gives a 1)
subtract the 1, if you get one.
divide by 2. This have to be done digit by digit as in elementary school :-)
repeat this until your decimalnumber become zero.
I wrote a function for this
function strMod2(array $dec)
{
return ((int)end($dec)) % 2;
}
function strDivBy2(array $dec)
{
$res = [];
$carry = 0;
if($dec[0] == '0')
array_shift($dec);
$len = count($dec);
for($i = 0; $i < $len; $i++)
{
$num = $carry*10 + ((int)$dec[$i]);
$carry = $num % 2;
$num -= $carry;
$res[] = $num / 2;
}
return $res;
}
function dec2bin_str($dec)
{
$dec_arr = str_split($dec);
$bin_arr = [];
while(count($dec_arr) > 1 || $dec_arr[0] != 0)
{
array_unshift($bin_arr, strMod2($dec_arr));
$dec_arr = strDivBy2($dec_arr);
}
return implode($bin_arr);
}
You can use it as
echo dec2bin_str('5'); // '101'
echo dec2bin_str('146456131894613465451'); // '1111111000001111100101101000000000000010100001100010101100101101011'
Maybe this can be done faster by using a library for big integers.
Found Math_BigInteger library that can do it:
$a = new Math_BigInteger($intString);
$base256IntString = $a->toBytes();
https://github.com/pear/Math_BigInteger

Statement match there condition

I have question regarding condition. Question is :
Combined length of any two sides of a triangle must be greater than the length of the third side for the segments to form a triangle. For example, 8, 6 and 12 can form a triangle because the sum of any two of the three segments is greater than the third segment. However, 24, 5, and 15 cannot form a triangle because the sum of segments 5 and 15 are not greater than the length of segment 24.
so, my coding is like this :
$aa = $_GET['a'];
$bb = $_GET['b'];
$cc = $_GET['c'];
if(($aa + $bb > $cc) || ($bb + $cc > $aa) || ($aa + $cc > $bb)){
echo"Triangle";
}
else{
echo"Not Triangle";
}
it can run, but, I test those number : 8, 6 and 12 and display Triangle. for number :24, 5, and 15 it also display Triangle even the answer is Not Triangle. Can anyone tell me why? TQ
Because all of these three conditions must be met, not single one. Replace
if(($aa + $bb > $cc) || ($bb + $cc > $aa) || ($aa + $cc > $bb)){
with
if(($aa + $bb > $cc) && ($bb + $cc > $aa) && ($aa + $cc > $bb)){
and you should be fine
It's easier if you consider that the combined length of the two shorter sides of the triangle must be greater than the length of the longest side... so if you sort the side lengths in order first so that you know which are the shortest and which is the longest, then the "if" logic is simplified
// Put our lengths into an array so that we can manipulate them more esily
$sideLengths = array($_GET['a'],$_GET['b'],$_GET['c']);
// Sort the array so that it's shortest to longest
sort($sideLengths);
// Test the sum of the two short sides against the longest
if (($sideLength[0] + $sideLength[1]) > $sideLength[2])
echo"Triangle";
} else {
echo"Not Triangle";
}

Categories