php array behaving strangely with key value 07 & 08 - php

I have an array for months
$months[01] = 'January';
$months[02] = 'February';
$months[03] = 'March';
$months[04] = 'April';
$months[05] = 'May';
$months[06] = 'June';
$months[07] = 'July';
$months[08] = 'August';
$months[09] = 'September';
$months[10] = 'October';
$months[11] = 'November';
$months[12] = 'December';
Now the array does not output correct value for key 07 & 08.
Try doing print_r($months) you will not get any key value August and zero key index for September.
Though I’m able to solve the problem by removing the leading zero, still I would love to know the reason for same.
Even the PHP editor spots some problem but unable to tell what is the problem.
Thanks

Prepending 0 before a number means PHP parses it as an octal value in the same way that prepending 0x causes it to be parsed as a hexadecimal value. Remove the zero, and it will work fine.
echo 07; // prints 7
echo 010; // prints 8
This is mostly used when specifying unix permissions:
chmod("myfile", 0660);
Except for that it's rarely something that you'd want to do.
This is described in the PHP Manual.

Generally, putting a leading 0 on a number tells the compiler that you've giving an octal number (base 8, not base 10).
In octal, 8 and 9 don't exist (8 is 010, 9 is 011), so you're confusing php.
If you really want a leading zero, you can use strings for your indexes

PHP will treat numbers with a leading 0 as octal numbers, either drop the leading 0 or put the key values in quotes.

The way you form an integer literal is important.
See the structure for decimal literals? Notice how a preceeding zero is not part of that pattern?
Either you have to remove the zeros, or treat your array keys as strings
$months['01'] = 'January';
$months['02'] = 'February';
// etc...

I just realized this after precious minutes of debugging and table head banging.
The problem is that PHP doesn't raise an error or even a warning about having malformed the octal literal integer. It just ignores the part from the error until the end of the literal.
Damn.
PS: Who uses octal numbers? never did, never heard of someone using them for a good reason.
Hexadecimal is great, but octal? damn.
Even for permission I usually do chmod ugo+rwx is more straightforward.

Related

Why strlen doesn't work in a paticular digit

I made this function. It seemed it's working but when it comes to 20 digits number, the return value was 19. I'm wondering why this problem happen..
My function
function sumDigits($n) {
return strlen($n);
}
echo sumDigits(100); //3
echo sumDigits(1000); //4
echo sumDigits(12345); //5
echo sumDigits(1000000000); //10
echo sumDigits(145874589632); //12
echo sumDigits(0); //1
echo sumDigits(12345698745254856320); //19 <-- Why not 20?
Can you please somebody explain for me?
Thank you so much.
First, I would point out that the name of your function is misleading, as you are not really summing the values of the digits, but are counting the digits. So I would call your function countDigits instead of sumDigits.
The reason why it doesn't work for large numbers, is that the string representation will switch to scientific notation, so you're actually getting the length of "1.2345698745255E+19" not of "12345698745254856320"
If you are only interested in integers, you will get better results with the logarithm:
function countDigits($n) {
return ceil(log10($n));
}
For numbers that have decimals, there is no good solution, since the precision of 64-bit floating pointing point numbers is limited to about 16 significant digits, so even if you provide more digits, the trailing decimals will be dropped -- this has nothing to do with your function, but with the precision of the number itself. For instance, you'll find that these two literals are equal:
if (1.123456789123456789123456789 == 1.12345678912345678) echo "equal";
Because you function parameter is an integer, exceeding the limit.
If you dump it, it actually shows the following:
1.2345698745255E+19 - which is 19 letters.
If you would do the following, it will return 20 - mind the quotes, which declares the input as string.
echo sumDigits("12345698745254856320"); //19 <-- Why not 20? -> now will be 20
As per documentation, strlen() expects a string so a cast happens. With default settings you get 1.2345698745255E+19:
var_dump((string)12345698745254856320);
string(19) "1.2345698745255E+19"
The root issue is that PHP converts your integer literal to float because it exceeds PHP_INT_MAX so it cannot be represented as integer:
var_dump(12345698745254856320, PHP_INT_MAX);
In 64-bit PHP:
float(1.2345698745254857E+19)
int(9223372036854775807)
You could change display settings to avoid E notation but you've already lost precision at this point.
Computer languages that store integers as a fixed amount of bytes do not allow arbitrary precision. Your best chance is to switch to strings:
var_dump('12345698745254856320', strlen('12345698745254856320'));
string(20) "12345698745254856320"
int(20)
... and optionally use an arbitrary precision library such as BCMath or GMP if you need actual maths.
It's also important to consider that this kind of issues is sometimes a symptom that your input data is not really meant to be an integer but just a very long digit-only string.

PHP BCMath cannot handle the exponential number if it is passed to its function, PHP BCMath return " bcmath function argument is not well-formed"

I working on the few of the small decimals like 0.0000687, 0.0000063241, 0.0000454. I used BCMath as to get the most precise result because it involved with money calculation, so far BCMath it is very helpfull to me in fixing my previous bug that I faced. But I found that BCMath cannot work well if the exponential value that automatically converted by PHP is being passed to BCMath. Below is the sample code :
$x = 0.00002123; // let say I got this value from the other computation;
// this $x value will automatically turn to exponential
// value by php because it have few of leading 0 after the '.'
The pattern where the PHP start to convert its real number into exponential number is : (see image below)
As you can see from the image above, the pattern of PHP start to convert real number to exponential number is when the leading 0 number is 4 times -> 0.0000xxxxx (pattern where PHP start to convert to exponential).
Then, let say this variable $x will be calculate into one of PHP BCMath function :
# First, I work with float number
$calculation1 = bcadd($x,5,12); // adding variable $x to 5
$calculation2 = bcmul($x,4,12); // multiply variable $x to 4
$calculation3 = bcdiv($x,5,12); // divide variable $x to 5
# Second, I tried to work with string number
$y = (string) $x;
$calculation4 = bcadd($y,5,12);
$calculation5 = bcmul($y,4,12);
$calculation6 = bcmul($y,4,12);
The result turn out to be error, here the screenshot for variable $x :
And here the result turn out to be error, here the screenshot for variable $y (pass to string first because BCMath works well working with string):
Important Note :
So it turn out BCMath have problem when working with exponential value, I cannot avoid this exponential value because PHP will automatically parse it to exponential number when it reach its pattern (can see image I attach above).
Considering where variable $x I get from different calculation, so in the real code, I cannot really hardcoded it to the way I want.
The bcmath functions in PHP work with numeric strings. Not floats and, importantly, not floats that have been cast to a string. This is mentioned in the extension's introduction:
Valid (aka. well-formed) BCMath numbers are strings which match the regular expression /^[+-]?[0]*[1-9]*[.]?[0-9]*$/.
Casting a float to a string in PHP will often give you a result in scientific notation - the 2.123E-5 syntax you're seeing in your results. bcmath cannot work with this representation; to match the regex above, the strings have to contain the argument in decimal form.
The warning you're seeing was added in PHP 7.4, and is listed on the Backward Incompatible Changes page for that version. Previously any non well-formed arguments were silently interpreted as zero (which wasn't exactly helpful).
As mentioned in the comments, the easiest way to convert a floating point number to its decimal form is with number_format, supplying the same precision that you are already using for the bc functions:
$precision = 12;
$x = 0.00002123;
echo bcadd(number_format($x, $precision), 5, $precision);
5.000021230000
See https://3v4l.org/SuWIu

Why does this happen in php when we multiple string by number it always gives zero(0)?

Suppose we have a string $str = "a"; and number $num = 2;
$str = 'a';
$num = 2;
echo $str*$num;
Output:
0
When performing arithmetic operations on a string operand, PHP will try to convert the string to a number.
It does this by looking for digits at the beginning of the string and will try to convert them into a value. If there are no digits, the value will be zero.
(There's an edge case for strings containing e or E (scientific notation), but that's not relevant here.)
Good Question.
Same i did ask to my teacher when i was in collage,
The answer is.
String * int= infinity; //According to scientific calculator answer is infinity.
but we need to continue our so program it provide 0.
it is made by code by default answer.
Simply said the string will be converted to an integer with a value of 0. This will include most of the cases when only alphabetic values are used. If you try to add a integer value at the beginning of the string it would in theory become a integer of that value.
I would recommend to read Why PHP Strings Equal Zero or Comparison Operators
Maybe you are looking for str_repeat, instead doing looping for that, its a default value that php serve to you, or you need to cast A into integer . When you try to do calculation for data that is not in Integer/float data type. Usually PHP auto-typecast the variables. In some cases it wont. Then we have to type cast it manually

Numeric values rounding down unexpectedly

I have a loop that calculates a couple revenue values then adds them together, like this:
$SalesGrowth = $C2012Sales+$C2011Sales;
In some cases, this works, and I get the expected, e.g.: 761.9 + 759.0 = 1520.9
In others, it looks like PHP randomly decides to round incorrectly (??) AND change the units (??) and I get:
8,788.0 + 8,794.3 = 16
What is going on here? I've even tried echoing out the separate sales values separated by a space, and they show up correctly, so the underlying figures aren't wrong.
Interpreted as a number, 8,788.0 is just 8, and parsing stops at the comma.
You'll need some locale-aware number parsing if you want to allow gimmicks like thousands-separators.
Update: If you have the Zend Framework, you can do this:
require_once('Zend/Locale/Format.php');
$locale = new Zend_Locale('en_GB'); // #1
$v = "8,410.5";
$n = Zend_Locale_Format::getNumber($v, array('locale' => $locale,'precision' => 3));
echo 2 * $number; // prints "16821"
Instead of hard-coding the locale, you could try and take it from the environment: new Zend_Locale(setlocale(LC_ALL, ""))
Dude the comma issue....
remove all the commas from the numbers before adding them...
str_replace(",","",$no1);
This is pretty simple... When you ask PHP to use the + operator, it will implicitly convert these strings such as "8,788.0" to an numeric value. Since you have a , character, it terminates the usefulness of the number, and it results in it being interpreted as 8. And so on...
Get rid of the non [0-9.] characters and it will work better.
Notice that 761.9 is a valid number, while 8,788.0 is not (from PHP's point of view).
So 8,788.0 in number context will evaluate as 8, just like 8,794.3. And 8+8 = 16.
To fix this problem, process your data to make numbers formatted properly.

Weird PHP behavior: won't assign the integer 8 to a variable

I think I just encountered the strangest 'bug' I've ever encountered in my short developer life. It seems like I just can't assign the value eight to any variable. For exemple:
<?php
$seven = 07;
$eight = 08; //what's wrong here?
$sevenB = 7;
$eightB = 8;
echo $seven;
echo $eight;
echo $sevenB;
echo $eightB;
?>
The output is:
7078
The debugger in NetBeans tells me 0 is assigned to $eight, while the other variables are fine.
If I remove the zeroes before the values, eight gets assigned, but as soon as this variable is used in a constructor, then it's replaced by zero again. WTF?
Here's my config: WAMP 2.0g, PHP 5.2.9, Apache 2.2.11, NetBeans 6.7.1.
Disabling Xdebug (2.05) doesn't change a thing.
Who is responsible for this inconsistent behavior? How to fix this?
Thanks for your help!
PHP treats numbers with a preceding 0 as an octal.
Re: PHP:Integers.
In PHP, a number that's prefaced by a zero is considered to be octal. Because octal (base 8) only has digits 0-7, 08 is invalid and treated as zero.
See this manual page for more information, and note the warning in the syntax section: "If an invalid digit is given in an octal integer (i.e. 8 or 9), the rest of the number is ignored."
<?php
var_dump(01090); // 010 octal = 8 decimal
?>
if you prefix your numbers with a zero (0) they are interpreted as octal numbers. 7 is the highest octal number. there’s also 0x for hexadecimal numbers (up to 15/F)
how to fix: just don’t prefix with 0 ;)
If your looking to lead a number with zero (Like a month calendar) you could try something like this:
<?
for ($num = 1; $num <= 31; $num++) {
if($num<10)
$day = "0$num"; // add the zero
else
$day = "$num"; // don't add the zero
echo "<p>$day</p>";
?>
Looks like everyone else also stated that a number leading with zero is treated as Octal
(s)printf is the only right way to do that.

Categories