Why does C print different values than what PHP prints? - php

This is a complete noob question.
So here is my code in C,
#include<stdio.h>
int main()
{
int I, X=4;
double I0;
double COEFF1[7];
double COEFF2[9];
/*Coefficient 1 I0*/
COEFF1[0]=0.0045813;
COEFF1[1]=0.0360768;
COEFF1[2]=0.2659732;
COEFF1[3]=1.2067492;
COEFF1[4]=3.0899424;
COEFF1[5]=3.5156229;
COEFF1[6]=1.0000000;
/*Coefficient 2 I0*/
COEFF2[0]=0.00392377;
COEFF2[1]=-0.01647633;
COEFF2[2]=0.02635537;
COEFF2[3]=-0.02057706;
COEFF2[4]=0.00916281;
COEFF2[5]=-0.00157565;
COEFF2[6]=0.00225319;
COEFF2[7]=0.01328592;
COEFF2[8]=0.39894228;
if(X>=3.75)
{
I0=COEFF2[0];
for(I=1;I<9;I++)
{
I0=(3.75/X)*I0+COEFF2[I];
printf("%i\n", I0);
}
//return I0/(sqrt(X)*exp(-X));
}
else
{
I0=COEFF1[0];
for(I=1;I<7;I++)
{
I0=I0*(X/3.75)*(X/3.75)+COEFF1[I];
}
//return I0;
}
return 0;
}
And with little housekeeping, this is my translated code in PHP,
<?php
$coeff1 =array();
$coeff2 =array();
/*Coefficient 1 $i0*/
$coeff1[0]=0.0045813;
$coeff1[1]=0.0360768;
$coeff1[2]=0.2659732;
$coeff1[3]=1.2067492;
$coeff1[4]=3.0899424;
$coeff1[5]=3.5156229;
$coeff1[6]=1.0000000;
/*Coefficient 2 $i0*/
$coeff2[0]=0.00392377;
$coeff2[1]=-0.01647633;
$coeff2[2]=0.02635537;
$coeff2[3]=-0.02057706;
$coeff2[4]=0.00916281;
$coeff2[5]=-0.00157565;
$coeff2[6]=0.00225319;
$coeff2[7]=0.01328592;
$coeff2[8]=0.39894228;
$x = 4;
if($x>=3.75)
{
$i0=$coeff2[0];
for($i=1;$i<9;$i++)
{
$i0=(3.75/$x)*$i0+$coeff2[$i];
printf($i0."<br />");
}
//return $i0/(sqrt($x)*exp(-$x));
}
else
{
$i0=$coeff1[0];
for($i=1;$i<7;$i++)
{
$i0=$i0*($x/3.75)*($x/3.75)+$coeff1[$i];
}
//return $i0;
}
?>
But why won't they generate the same result?
http://imageshack.com/a/img59/3402/98ak.jpg
Please help. I'm stuck.

%i is the format specifier for int; I0 has type double but printf is being told to interpret it as int. You should use %f for doubles instead:
printf("%f\n", I0);

Maybe this bit might be useful too.
The difference in the output of the two programs can be attributed indeed to the line
printf("%i\n", I0);
in your C program where I0 is interpreted as an integer but its bit pattern was stored as a double type which uses different logic for organizing the bits (and in the standard variation also uses a different number of bits). What the printf function does is that it just takes whatever that bit pattern was (in the length of an integer) and prints it out like it was an integer - because you told it so (%i), hence the output of the program.
PHP uses dynamic type definition so your variables are interpreted in the context in which they are used (unless sometimes forced to be a certain type by casting or using settype()).
I.e.: $a = 1; will be an integer but if you do another assignment like $a += 0.5; it will be casted into a float automatically.

Related

Why PHP number_format() change the number? [duplicate]

I am working with huge numbers for website purposes and I need long calculation. When I echo a long number I don't get the correct output.
Example
// A random number
$x = 100000000000000000000000000;
$x = number_format($x);
echo "The number is: $x <br>";
// Result: 100,000,000,000,000,004,764,729,344
// I'm not getting the value assigned to $x
Your number is actually too big for php standard integers. php uses 64 bit integers which can hold values within range -9223372036854775808 (PHP_INT_MIN)
to +9223372036854775807 (PHP_INT_MAX).
Your number is about 87 bits long which simply is too much.
If you really need such big numbers you should use the php BC math types, explained in the manual: http://php.net/manual/en/ref.bc.php
If you just want to format a string formed like a huge number then use something like this:
function number_format_string($number) {
return strrev(implode(',', str_split(strrev($number), 3)));
}
$x = '100000000000000000000000000';
$x = number_format_string($x);
echo "The number is: $x\n";
// Output: The number is: 100,000,000,000,000,000,000,000,000
Edit:
Added strrev() to function because the string needs to be reversed before splitting it up (thanks to #ceeee for the hint). This ensures that the delimiter is placed at right position when length of input is not divisible by 3. Generated string needs to be reversed afterwards again.
Working example can be found at http://sandbox.onlinephpfunctions.com/code/c10fc9b9e2c65a27710fb6be3a0202ad492e3e9a
answer #maxhb has bug. if the input is '10000000000000000000000' the out put would be:
The number is: 100,000,000,000,000,000,000,00
Which is incorrect. So try below code:
function number_format_string($number, $delimeter = ',')
{
return strrev(implode($delimeter, str_split(strrev($number), 3)));
}
$x = '10000000000000000000000';
$x = number_format_string($x);
echo "The number is: $x\n";
// Output: The number is: 10,000,000,000,000,000,000,000
The largest integer that can be represented in a 64bit PHP install, compared to your number:
9,223,372,036,854,775,808 - largest possible signed 64bit integer
100000000000000000000000000 - your number
since you're exceeding the maximum number size, you can't expect to get useful results without using something like gmp/bcmath.
PHP does not yet support formatting long numbers, even when you always keep them as strings in your code (to avoid issues with PHP’s int type):
php > echo number_format('100000000000000000000000000');
100,000,000,000,000,004,764,729,344
php > echo number_format('3.14159265358979323846', 20);
3.14159265358979311600
The underlying ICU library supports formatting arbitrary precision decimal numbers, but PHP doesn’t use the relevant function yet – see request #76093.
http://php.net/manual/en/function.number-format.php
That is the solution:
<?php
# Output easy-to-read numbers
# by james at bandit.co.nz
function bd_nice_number($n) {
// first strip any formatting;
$n = (0+str_replace(",","",$n));
// is this a number?
if(!is_numeric($n)) return false;
// now filter it;
if($n>1000000000000) return round(($n/1000000000000),1).' trillion';
else if($n>1000000000) return round(($n/1000000000),1).' billion';
else if($n>1000000) return round(($n/1000000),1).' million';
else if($n>1000) return round(($n/1000),1).' thousand';
return number_format($n);
}
?>

Get negative numbers after conversion to float [duplicate]

I am trying to convert a hex string into a signed integer.
I am able to easily transfer it into an unsigned value with hexdec() but this does not give a signed value.
Edit:
code in VB - the two "AA" hex values are representative.
Dim bs(2) As Byte
bs(1) = "AA"
bs(2) = "AA"
Dim s As Short
s = BitConverter.ToInt16(bs, 1)
Check out this comment via php.net:
hexdec() returns unsigned integers. For example hexdec("FFFFFFFE") returns 4294967294, not -2. To convert to signed 32-bit integer you may do:
<?php
echo reset(unpack("l", pack("l", hexdec("FFFFFFFE"))));
?>
As said on the hexdec manual page :
The function can now convert values
that are to big for the platforms
integer type, it will return the value
as float instead in that case.
If you want to get some kind of big integer (not float), you'll need it stored inside a string... This might be possible using BC Math functions.
For instance, if you look in the comments of the hexdec manual page, you'll find this note
If you adapt that function a bit, to avoid a notice, you'll get :
function bchexdec($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
return $dec;
}
(This function has be copied from the note I linked to ; and only a bit adapted by me)
And using it on your number :
$h = 'D5CE3E462533364B';
$f = bchexdec($h);
var_dump($f);
The output will be :
string '15406319846273791563' (length=20)
So, not the kind of big float you had ; and seems OK with what you are expecting :
Result from calc.exe =
15406319846273791563
Hope this help ;-)
And, yes, user notes on the PHP documentation are sometimes a real gold mine ;-)
I've been trying to find a decent answer to this question and so I wrote this function which works well for a Hex string input, returning a signed decimal value.
public function hex_to_signed_int($hex_str){
$dec = hexdec($hex_str);
//test is value negative
if($dec & pow(16,strlen($hex_str))/2 ){ return $dec-pow(16,strlen($hex_str));}
return $dec;
}

MySQL decimal fields returned as strings in PHP

By default mysqli returns all values as strings, the MYSQLI_OPT_INT_AND_FLOAT_NATIVE option allows you to convert ints and floats to their appropriate types. Though this does not affect decimal fields.
Is there a way to automatically cast all decimal fields to a php float type without manually calling $value = (float) $row->some_decimal_field?
I highly doubt it. Decimals use fixed point math, and there is no data type in PHP that can provide this. Floats come close, but they are in fact rounded, meaning that assigning 2 to a float could result in 1.99999999999999999 instead. So even if MySQL offers a way to get a decimal into a PHP float, you are risking loss of data by casting from a decimal to a float.
To handle this cleanly, you'd need something like GMP, but as you can probably guess MySQL can't provide that for you automatically. You will need to do it manually in PHP.
Here is something that you can do with PHP to solve the problem:
function string_to_float($foo){
if($foo*1==$foo && !empty($foo)){
return $foo*1;
} else {
return $foo;
}
}
string_to_float($row->some_decimal_field);
The real question is, Why do you need to convert the type of the decimal string? If you are trying to use it in math, php will make the conversion automatically for you. As a decimal string is equivalent to a float with the same value. Here is a simple test:
$foo = "1.2";
$bar = 1.2;
if($foo===$bar){
$equivalent = "is";
} else {
$equivalent = "is not";
}
print '"1.2" '.$equivalent.' equal to 1.2 in type and value<br />';
if($foo==$bar){
$equivalent = "is";
} else {
$equivalent = "is not";
}
print '"1.2" '.$equivalent.' equal to 1.2 in value<br />';
$foo = "1.2"*1;
$bar = 1.2;
if($foo===$bar){
$equivalent = "is";
} else {
$equivalent = "is not";
}
print '"1.2"*1 '.$equivalent.' equal to 1.2 in type and value<br />';
which will return:
"1.2" is not equal to 1.2 in type and value
"1.2" is equal to 1.2 in value
"1.2"*1 is equal to 1.2 in type and value

Issue with float multiplication and evaluation

This problem is best expressed in code:
$var1 = 286.46; // user input data
$var2 = 3646; // user input data
$var3 = 25000; // minumum amount allowed
$var4 = ($var1 * 100) - $var2; // = 250000
if ($var4 < $var3) { // if 250000 < 250000
print 'This returns!';
}
var_dump($var4) outputs: float(25000) and when cast to int, outputs: int(24999) - and thereby lies the problem.
I don't really know what to do about it though. The issue occurs upon multiplication by 100, and while there are little tricks I can do to get around that (such as *10*10) I'd like to know if there's a 'real' solution to this problem.
Thanks :)
This is a horrible hacky solution and I slightly hate myself for it, but this gives the expected behaviour:
<?php
$var1 = 286.46; // user input data
$var2 = 3646; // user input data
$var3 = 25000; // minumum amount allowed
$var4 = ($var1 * 100) - $var2; // = 250000
if ((string) $var4 < (string) $var3) { // if 250000 < 250000
print 'This returns!';
}
Cast them to strings, and they get converted back to int/float as appropriate for the comparison. I don't like it but it does work.
Really you need BC Math for precise floating point mathematics in PHP.
Its always a good idea to use ceil (or floor based on what you want) when using float number as int
In your case try ceil($var4) before comparison!
That's what floats do sometimes, it is all due to how floats are unable to precisely represent integers from time to time.
Instead of casting it to an int, you can round the number to an integer value and then cast it to an int. (possibly that cast unnecessary, but PHP isn't to clear about how such things happen internally, and even if you know how they happen right now, they may not in the future.
I think you could use bccomp for comparing floating point values but i think it's a function that's not in the PHP Core.
Otherwise i found this function here but i couldn't test it to see if it works
function Comp($Num1,$Num2,$Scale=null) {
// check if they're valid positive numbers, extract the whole numbers and decimals
if(!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num1,$Tmp1)||
!preg_match("/^\+?(\d+)(\.\d+)?$/",$Num2,$Tmp2)) return('0');
// remove leading zeroes from whole numbers
$Num1=ltrim($Tmp1[1],'0');
$Num2=ltrim($Tmp2[1],'0');
// first, we can just check the lengths of the numbers, this can help save processing time
// if $Num1 is longer than $Num2, return 1.. vice versa with the next step.
if(strlen($Num1)>strlen($Num2)) return(1);
else {
if(strlen($Num1)<strlen($Num2)) return(-1);
// if the two numbers are of equal length, we check digit-by-digit
else {
// remove ending zeroes from decimals and remove point
$Dec1=isset($Tmp1[2])?rtrim(substr($Tmp1[2],1),'0'):'';
$Dec2=isset($Tmp2[2])?rtrim(substr($Tmp2[2],1),'0'):'';
// if the user defined $Scale, then make sure we use that only
if($Scale!=null) {
$Dec1=substr($Dec1,0,$Scale);
$Dec2=substr($Dec2,0,$Scale);
}
// calculate the longest length of decimals
$DLen=max(strlen($Dec1),strlen($Dec2));
// append the padded decimals onto the end of the whole numbers
$Num1.=str_pad($Dec1,$DLen,'0');
$Num2.=str_pad($Dec2,$DLen,'0');
// check digit-by-digit, if they have a difference, return 1 or -1 (greater/lower than)
for($i=0;$i<strlen($Num1);$i++) {
if((int)$Num1{$i}>(int)$Num2{$i}) return(1);
else
if((int)$Num1{$i}<(int)$Num2{$i}) return(-1);
}
// if the two numbers have no difference (they're the same).. return 0
return(0);
}
}
}
The problem is that floats just cannot represent some numbers. Since PHP doesn't have a "decimal" (or other fixed-point) type, you can basically only hack your way around these problems.
Assuming the first number in your example $var1 = 286.46 denotes some kind of money, you could just convert that to cents directly after the user entered it (e.g. through stripping the point and reading it as an integer) and thus calculate everything using integer math.
That's not a general solution - and I doubt that one exists (short of using arbitrary precision numbers, which some PHP extensions provide - but I that smells like overkill to me).

Less than operator not working correctly in PHP 5.3.1

For the purpose of the example, var 2 is preset from a database as "147.22" type STRING. var 1 is calculated previously in the script and has 147.22 type FLOAT.
Script:
<?
$var1 = (float)$var1;
$var2 = (float)$var2;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
My expected results would be that the script NOT echo "hello" since the two values are equal in amount and type.
However here is the output I'm getting:
float(197.22)
float(197.22)
hello
If I do not mess with the types and leave the one a float and the other a string, then it still does not work (this is how I got here in the first place).
If i force the values at the time of execution like this:
$var1 = 147.22;
$var2 = 147.22;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
I get this, (and it works):
float(197.22)
float(197.22)
Notice no "hello"....
Anyone have any clue wth is going on here?
If one of the floats is calculated numerically, and one is created from string assignment, they could be different. Try the following:
$x = 147.22;
$y = 147.2200000000001;
printf("%.40f\n", $x);
printf("%.40f\n", $y);
var_dump($x);
var_dump($y);
var_dump($x < $y);
outputs
147.2199999999999988631316227838397026062012
147.2200000000001125499693443998694419860840
float(147.22)
float(147.22)
bool(true)
Cast them to a string with a specified precision for comparison.
If you are dealing with floats, then it's not safe to compare them directly, because there may be rounding or representation issues.
You'd better to check if the difference between those numbers is less than some predefined and very minimal epsilon, and then determine if they're equal, or which is the greater one.
This discussion may be worth reading: Is casting to float destructive?
EDIT:
More discussions to read:
PHP: Floating point numbers
php integer and float comparison mismatch

Categories