tags:

views:

177

answers:

7
+4  Q: 

PHP Leftmost digit

Hi,

let's say I have a variable containing an integer or a float (since integers might overflow into a float in PHP).

I want to run some operation to get the leftmost digit and the rest of the remaining digits.

To explain better:

<?php

$x   = NULL;  //this will hold first digit
$num = 12345; //int

/// run operation


//outputs
//$x   = 1;
//$num = 2345;
var_dump($x, $num);

?>

Now, I know there's multitudes of ways to do this if you represent the number as a string, but I'm trying to avoid type casting it into a string.

I'm probably looking for a solution which includes bitwise operations, but I'm pretty weak in that topic so I'm hoping someone who usually works low-level might be able to answer this!

Thanks a bunch.

+10  A: 

I'm sure there is a way to do this without casting it to a string, but why? The string detour is so easy:

$x = (int)substr($num, 0, 1); 

It'll give you a nice, proper integer.

Obviously, this does no extended checking for faulty input, and requires $num to be a valid number.

Pekka
or $x = (int) $num{0};
fire
PHP Manual: Strings may also be accessed using braces, as in $str{42}, for the same purpose. However, this syntax is deprecated as of PHP 5.3.0. Use square brackets instead, such as $str[42].
konforce
A: 

To get the rest of the digits

$remainingnum = (int)substr((string)$num, 1, strlen($num));

liamfriel
A: 

If you typcast the value to a string you can use the array type selector.

For example:

$n = (string)12345676543.876543;
echo (int)$n[0];
RobertPitt
+7  A: 

Avoids using any string manipulation, but no guarantees for float or even negative values

$x   = NULL;  //this will hold first digit
$num = 12345; //int

$m = 1;
while(true) {
    $m *= 10;
    if ($m > $num)
        break;
}

$m /= 10;

$x = (int) floor($num / $m);
$num = $num % $m;


//outputs
//$x   = 1;
//$num = 2345;
var_dump($x, $num);
Mark Baker
I'll check this out, thanks.
ninuhadida
If you want to work with float as well, then you'll need to replace $num = $num % $m; with $num = fmod($num,$m);
Mark Baker
I don't understand why casting the string to string and back is out of the question, but +1 for an answer that does what the OP wants.
Pekka
I want to benchmark the difference between mathematical solution / string manipulation. I know, optimization is the root of all evil, but I'm working on thousands of numbers and I got some extra time to fool around.
ninuhadida
I'd wager that string manipulation would be faster, but you might want to look at micro-optimising the while loop before running any performance tests because that's not particularly efficient
Mark Baker
From my own testing:`return floor($num/pow(10,(floor((log10($num))))));` takes 0.000005seconds and `return (int)substr($num, 0, 1);` takes 0.000004seconds. Size of the number does not show any change in processing time.
A: 

@Mark Baker offered the best solution, though you should do abs(floor($num)) before applying the algorithm.

Mikhail
+7  A: 

Math-only method:

function leftMost($num) {  
    return floor($num/pow(10,(floor((log10($num))))));
}

explained I guess...

1+ log10 of num calculates the number of digits a number is, we floor it to remove any decimal values, put it as the exponent so for a 1 digit number we get 10^0=1, or a 8 digit number we get 10^8. We then are just divding 12345678/10000000 = 1.2345678, which gets floor'd and is just 1.

note: this works for numbers between zero and one also, where it will return the 2 in 0.02, and a string transform will fail.

If you want to work with negative numbers, make $num = abs($num) first.

That's a lovely solution!
Andrew
I get the result 881 from `$num = 12345`.
Mike
Sorry, I used 10^ instead of pow().
Nice use of math
Mark Baker
This does not work for negative numbers or 0. You should use abs($num) to guarantee it is positive and return 0 for the special case of 0. Alternatively, you could throw an error if $num <= 0?
adamnfish
@adamnfish I mentioned that in one of my edits. Also, zero is the worst number of all time. ALL TIME. -- Reason it doesn't work for 0, because log10(0) is at negative infinity.
Your solution is great, though the correct answer had to go to Mark Baker since he showed how to get the remaining digits as well. That said, thanks a lot for your solution!
ninuhadida
Wait, why does `10^` not work but `pow()` works? What is the difference?
Lèse majesté
@lese ^ is the bitwise XOR.
Ah, dur.... I shoulda known that one.
Lèse majesté
A: 

I know you stated you wanted to avoid casting to a string, but if you want to loop over the digits in PHP, this will be the fastest way:

$len = strlen($n);
for ($i = 0; $i < $len; ++$i)
  $d = $n[$i];

In a quick-and-dirty benchmark, it was around 50% faster than the equivalent set of mathematical expressions, even when minimizing the calls to log and exp.

konforce