Parsing of decimal numbers (with decimal point) as kind of value

I was trying to implement a tunable radio and came across some strangeness. First, it appears that the auto-generated parse token for a new kind of value does not handle over-precision in the same way that the parse token for real numbers does. Second, it appears that over-precision with only leading zeroes in the legitimate precision range (and beyond) can result in the parse token incorrectly interpreting the number. Third, it appears that rounding of precision when converting real numbers to a real number-based kind of value does not happen at .5 as would be expected.

Following is the example code. Note that the check rule attempts to handle the player dropping the units part of a frequency:

"Unit Interpretation Issues"

Place is a room.

A frequency is a kind of value. 99.999 MHz specifies a frequency. 99 MHz specifies a frequency scaled up by 1000. [EDIT: On second look, I'm pretty sure that this combination of specifications should be illegal.]

The player carries a device called a shortwave radio. The shortwave radio has a frequency called current frequency.

The block setting it to rule does nothing when the noun is the radio.

The setting it to action has a frequency called interpreted value.

To decide which frequency is (N - real number) as a frequency: [dodge conversion issue]
    (- REAL_NUMBER_TY_TIMES({N}, 1000) -).

Check setting the radio to (this is the can only set to a frequency rule):
    if the topic understood matches "[frequency]":
	    now interpreted value is the frequency understood;
	    say "<direct freq value = [interpreted value]>";
    otherwise if the topic understood matches "[real number]":
	    now interpreted value is the real number understood as a frequency;
	    say "<real number freq value = [interpreted value]>";
    otherwise:
	    say "You can only set it to a frequency." instead.

Report setting the radio to (this is the successful tuning report rule):
    say "The radio is now set to [interpreted value]."

Test me with "set radio to 11 / set radio to 1.234 mhz / set radio to 9.000009 mhz / set radio to 11.2341 / set radio to 11.2349 / set radio to 11.2345 / set radio to 11.23450 / set radio to 11.23451 / set radio to 11.234501 / set radio to 11.2349 mhz".

Interestingly, the parsing routine produced by the “scaled up by 1000” specification does handle leading zeroes after the decimal correctly, but it does not handle rounding to match precision at all.

Are the generated parsing routines created purely within the I7 compiler and therefore not modifiable through the template layer?

This is more about how unit specifications work and less about the parser. 99.999 MHz specifies a frequency only looks like we’re talking about a real number. Basically anything in these specifications that isn’t a numeral is an arbitrary symbol, so that’s analagous to 99|999 specifies a fubar with parts foo and bar. So it’s two separate integers. And just like you can have gratuitous 0-left-padding in number literals: xyz is initially 0000000000000001 you can have gratuitous 0-left-padding in either or both parts of a two-part value: let q be the fubar with foo part 000034 and bar part 00056. And the literals work the same way. With q is initially 000034|056, you end up with foo of 34 and bar of 56, but if you say q, it’ll be “34|056” because Inform knows bars are supposed to be three digits. Worse, if you say “34|0560” bar is 560. So if one had used . instead of | one would end up with 0.0560 seemingly being ten times larger than 0.056.

I’d been going to say that I’m surprised it accepted 99 MHz is a frequency scaled up, that that should probably be illegal, but now I see your edit in which you concluded the same.

I think life’d probably be easier with:

tuning is an action applying to one thing and one real number.
Understand the command "set" as something new.
Understand "set [thing] to [real number] MHz/--" as tuning.

carry out tuning the radio: now the current frequency of the radio is the real number understood.

report tuning the radio: say "The radio is now set to [current frequency of the radio to 3 decimal places] MHz."

The player carries a device called a shortwave radio. The shortwave radio has a real number called current frequency.

But this has the drawback of allowing the player to specify ridiculous precision in their command without being able to comment on it.

2 Likes

Many thanks! I believe that you are correct in all respects. That the decimal point has no special significance in the specification pattern is the important part.

It seems that part of the issue is that I should have used just one specification with “scaled at” – if done that way, the generated parse token will handle decimal values (at least to the number of decimal places allowed by the scaling) and will not incorrectly interpret over-precision with too many leading zeroes after the decimal (by virtue of the token failing).

A frequency is a kind of value. 99 MHz specifies a frequency scaled at 1000.

The rounding issue is somewhere else.

2 Likes

Now I see what you mean about rounding. Floating point representation and rounding strategies get weird pretty quickly. I’m not sure exactly what’s in play.

1 Like