Knocking around the UNITS system trying things, I’ve found at least two (seemingly, different) problems with Inform’s built-in math routines. The answer Inform gives is actually not mathematically correct. These are problems with very common operations like simple multiplication and even addition, so I would be surprised if these are not already known issues, thus I have not reported them yet as bugs and have been thinking about them for about a week wondering if I just miscalculated something, but I don’t think so. Math is math…
Both issues are with Inform’s system of fractional math. The first occurs when you simply scale a number with a non-base-10 value. For example…
[code]The Kitchen is a room. Filesize is a kind of value. 1KB specifies a filesize. 1MB specifies a filesize scaled up by 1024.
X, Y, and Z are filesizes that vary.
X is 500KB. Y is 700KB.
When play begins:
showme x;
showme y;
now z is x + y;
showme z;
now z is z - 700KB;
showme z.[/code]
The first value returned for Z is off – it returns 1.1729MB when the answer should be 1.1719MB – and the error is larger by an order of magnitude than the margin of error you would expect from the scaling (I would expect the 4th decimal place to possibly be wrong or omitted, but not the third, that’s too much error). However, it seems the value is being stored correctly, because subtracting 700KB from Z results in the correct value, so the mistake only appears when printing a scale-shifted result (and furthermore only when printing a result scale-shifted via a non-base-10 scale).
The other flaw is much simpler and I’d be surprised if people didn’t know about it already. Multiplying and dividing compound units (i.e. ‘6 foot 2’ or ‘8 lb 5 oz’) by each other produces results that are way off, usually by an order of magnitude – and the whole number, not just one digit. Witness the disastrous results of my attempt to create an (apparently) unitless, single-decimal-place number type…
[code]The Kitchen is a room. A single-decimal-place number is a kind of value.
1.9 specifies a single-decimal-place number with parts integer and decimal.
A single-decimal-place number times a single-decimal-place number specifies a single-decimal-place number.
When play begins:
let p be 1.9;
let q be 7.5;
let r be p * q;
let s be p / q;
showme r;
showme s.[/code]
Multiplication inflates the results when multiplying compound units together, in this case by a factor of 10. Division lowballs the result by a factor of I think either 100 or 1000 in this case; though I don’t remember specifically – you can probably work it out from the ‘To decide’ routine I ended up with to compensate (see below).
I was finally able to create a somewhat mathematically usable, compound unit, but after correcting for Inform’s errors, it isn’t exactly pretty. With multiplication it was easy: I just fudged it. With division the necessary precision gets lost, so the only way was to convert the whole thing to integer math and then back again (but something janky seems to be going on there, too, because I had to scale the dividend up by an order of magnitude more than I expected, to get the right answer out even using integer math, or maybe I just miscalculated at first, but anyway by trial & error, I basically just added factors of 10, until I got the right answer).
The below will probably have to be modified to compensate for a different level of error if you use non-base-10 scaling or if want greater than one decimal place of precision, but these additional ‘To decide’ routines or something like them seems necessary to get accurate co-multiplication or co-division out of a compound (i.e. two part) unit kind: please correct me if I am wrong…
[code]The Kitchen is a room.
A single-decimal-place number is a kind of value.
1.9 specifies a single-decimal-place number with parts integer and decimal.
A single-decimal-place number times a single-decimal-place number specifies a single-decimal-place number.
To decide which single-decimal-place number is (x - a single-decimal-place number) multiplied correctly by (y - a single-decimal-place number):
let z be x * y;
decide on z / 10.
To decide which single-decimal-place number is (x - a single-decimal-place number) divided correctly by (y - a single-decimal-place number):
let xk be 10 * the integer part of x;
now xk is xk + the decimal part of x;
now xk is xk * 100;
let yk be 10 * the integer part of y;
now yk is yk + the decimal part of y;
let zk be xk / yk;
now zk is zk / 10;
let zi be zk / 10;
let zd be the remainder after dividing zk by 10;
decide on the single-decimal-place number with integer part zi decimal part zd.
When play begins:
let p be 1.9;
let q be 7.5;
let r be p multiplied correctly by q;
let s be p divided correctly by q;
showme r;
showme s.[/code]
Paul.
EDIT: Damn, I have not tried this in 6G60 yet. I really should have — I will later.