XOR ^= for loop

So I have been experimenting with some single complex lines of code and ran across this:

[php]function roman_numerals($num){
$c = ‘IVXLCDM’;
$num = return_whole_number ($num);

for($a = 5, $b = $s = ''; $num; $b++, $a^=7) {
	for ($o = $num % $a, $num = $num / $a ^ 0; $o--; @$s = $c[$o > 2 ? $b + $num - ($num &= -2) + $o = 1 : $b] . $s) ;
}
return $s;

}[/php]

The original code did not have the suppression added to it, I added them to hide an error that was being generated, although I am not so much worried about the error right now, I am more interested in the concept of this code… I find this fascinating.

Let me give an example, if I call:

[php]echo roman_numerals(2178);[/php] it’s output would be, as expected MMCLXXVIII

OK, I am finding this pretty cool, but now the question is WHY?

The first for loop, why is $a starting at 5? it look like it is going through a loop of 5 and 2. Am I wrong on this?

Then the second loop… Ok, $o is the number being assigned, now it takes the number dividing it by the XOR 5 or 2 then giving a power of 0? Yeah, this has got me on that… Can anyone explain how this works?

Thank you

OK, I have broken this down a little more, here is what I have come up with:
[php]<?php
define(‘BR’, “
”);

function roman_numerals($num){
$c = ‘IVXLCDM’;

for($a = 5, $b = $s = ''; $num; $b++, $a^=7) {
    echo 'a: '.$a.BR;
    for ($o = $num % $a, $num = $num / $a ^ 0; $o--; $s = $c[$o > 2 ? $b + $num - ($num &= -2) + $o = 1 : $b] . $s) {
        echo 'o: '.$o.BR;
        echo 'num: '.$num.BR;
        echo 'a2: '.$a.BR;
        echo 'b: '.$b.BR;
        echo 's: '.$s.BR;
        echo 'c: '.$c.BR;
    }
}
return $s;

}

echo roman_numerals(578).BR;[/php]

This now outputs:
a: 5
o: 2
num: 115
a2: 5
b:
s:
c: IVXLCDM
o: 1
num: 115
a2: 5
b:
s: I
c: IVXLCDM
o: 0
num: 115
a2: 5
b:
s: II
c: IVXLCDM
a: 2
o: 0
num: 57
a2: 2
b: 1
s: III
c: IVXLCDM
a: 5
o: 1
num: 11
a2: 5
b: 2
s: VIII
c: IVXLCDM
o: 0
num: 11
a2: 5
b: 2
s: XVIII
c: IVXLCDM
a: 2
o: 0
num: 5
a2: 2
b: 3
s: XXVIII
c: IVXLCDM
a: 5
a: 2
o: 0
num: 0
a2: 2
b: 5
s: LXXVIII
c: IVXLCDM
DLXXVIII

OK, so, as I expected, 5 and 2 in the first loop
Now the mess in the middle… HAHA

Too bad John Nash isn’t still alive! ;D Sorry, just my way of saying this is way above me. :wink:

So far, this is what I figured out:

Loop 1:
Alternate between 5 and 2 dependent on how many times it is divisible between 5 and 2

Loop 2:
Divide the number by its first loop (which is 5), and give the $num a floor value (which is 578 / 5 - floor 115) leaves a remainder of 2 which is the value of $o. So loop until this is 0… Continuing with the second loop, $o has a value of 2, $s will have no value, then loop and subtract from $o which now has a value of 1, give $s its first value of “I”, and loop again $o now equals 0 and give $s the next “I” so $s now has a value of “II” and The first loop of 5 is now completed…

This is where I start to get lost… When I was in school (20+ years ago) we had to memorize roman numerals,

I = 1
V = 5
X = 10
L = 50
C = 100
D = 500
M = 1000
(Yay I remember… HAHA) I didn’t know there was an actual formula to calculate its value… I guess this is what I am trying to figure out from this. I don’t know, I just think this is neat!

AH HA!
OK, here is the magic: $c[$o > 2 ? $b + $num - ($num &= -2) + $o = 1 : $b]

I wasn’t paying attention to the [ ] so… if $o > 2 then grab the value of $b + $num - ($num &= -2) + $o = 1 else $b

So, if $o = 2 then $c = 1 (example $c[1])
If $o = 1 then $c = 1 ($example $c[1])

But if $o = 5 then $c = 2 (example $c[2])

so on and so on…

It is basically grabbing the letter of the string $c dependent on the number of divisions… I see it in my head, hard to explain. This is much easier then I thought at the beginning… Still really cool in my book! +1 to the person who figured this out.

Sponsor our Newsletter | Privacy Policy | Terms of Service