Unexpected arithmetic results - why?

A weird one:

"Odd Numbers"

Place is a room.

To decide which text is (N - number) recalculated:
[	showme N;
    showme (N divided by 256) to the nearest whole number;
    showme the remainder after dividing N by 256;] [same behavior from showme]
    say "word = [N] ";
    let HB be (N divided by 256) to the nearest whole number;
    say "high = [HB] ";
    let LB be the remainder after dividing N by 256;
	say "low = [LB] // ";
    [decide on "[HB] [LB]".] [uncomment this and everything works fine]

After jumping:
    let N be 5;
    say "[N] -> [N recalculated][line break]".

Test me with "jump".

which yields:

>JUMP
5 -> word = 505262 high = 1973 low = 174 // 

but when the last line of the decide phrase is uncommented the calculations work as expected:

>JUMP
5 -> word = 5 high = 0 low = 5 // 0 5

Why the strange change in the laws of arithmetic here?

Your example, as it stands with the last line commented out, is arguably invalid code that the compiler should reject (since we have a “to decide” phrase that never decides on anything).

With the decide on line in place, the compiler generates the following “wrapper function”:

! Request 0: phrase number -> text
! To decide which text is ( N - number ) recalculated:
[ PHR_799_r0  I7RBLK 
    t_0 ! Call parameter 'N': number
;
    @push I7SFRAME;
    StackFrameCreate(4);
    BlkValueCreateOnStack(2, TEXT_TY);
    BlkValueCreateOnStack(0, TEXT_TY);
    I7RBLK = BlkValueCopy(I7RBLK, KERNEL_4(t_0));
    BlkValueFreeOnStack(2);
    BlkValueFreeOnStack(0);
    @pull I7SFRAME;
    return I7RBLK; ! text
];
[ KERNEL_4 
    t_0 ! Call parameter 'N': number
    tmp_0 ! Let/loop value, e.g., 'HB': number
    tmp_1 ! Let/loop value, e.g., 'LB': number
    ;
    ! ... the requested calculations ...
    return BlkValueCopy(I7SFRAME, ((LocalParking-->0=t_0),(LocalParking-->1=tmp_0),(LocalParking-->2=tmp_1),TEXT_TY_ExpandIfPerishable((I7SFRAME+WORDSIZE*2),TX_S_392)));
    return BC_162;
];

The first parameter to the PHR_ function (the one being called by our jumping rule) is I7RBLK, presumably a sort of pointer by which the text value is returned, while our N parameter comes second.

! In the "after jumping" rule
print (TEXT_TY_Say) (PHR_799_r0 (I7SFRAME,tmp_0));

In the version in which we never decide on anything, the rule still calls our phrase in the same manner (with N as the second parameter), but the phrase definition now looks like this:

! Request 0: phrase number -> text
! To decide which text is ( N - number ) recalculated:
[ PHR_799_r0  
    t_0 ! Call parameter 'N': number
    tmp_0 ! Let/loop value, e.g., 'HB': number
    tmp_1 ! Let/loop value, e.g., 'LB': number
    ;
    ! [2: say ~word = [N] ~]
    say__p=1;! [3: ~word = ~]
    ParaContent(); print "word = ";! [4: n]
    ! ... calculations and stuff ...
    ParaContent(); print " // "; .L_Say295; .L_SayX295;return BC_162;
];

Gone is the wrapper function, and now the phrase expects N to be the first parameter – which it isn’t, of course. In essence, without the “decide on” in there, you’re doing calculations with the return pointer rather than your number.

(Also, where do you keep digging up these edge cases? :smile: )

1 Like

Hm, the superstitious peasant in me is wary that the phrase is deciding on “a number”, not a real number. Is it possible the automated integer->real number conversions we expect Inform to perform aren’t happening in this decide phrase where no decision has been made? Sort of an edge case or bug situation?

Edit - Ah I see our learned friend has already supplied a solution while I typed this. But I’m glad I was a bit close.

-Wade

You’ll note that in the generated I6, it decides on the empty text, a reasonable inference given the code. The argument mismatch seems to be the real issue.

I once heard someone describe Inform 7 as “the best puzzle game that Graham Nelson ever wrote.” I’m just a dedicated playtester, I guess.

3 Likes