We’ve wanted floating-point numbers in Glulx for a while now. I7 can handle fixed-point numbers, if you set up the units and the number of decimal places that you want. But floats are more familiar in the programming world.
Floats are a moderate nuisance for Glulx, because all of its variables and data handling are for 32-bit integers. So we need a way to store a float in an integer, which, conveniently, has been defined for decades now – it’s called IEEE-754. We also need some code to convert from native float values to this standardized form. After letting the idea gather dust, I mean percolate, for the past several years, I finally went Googling and found that code.
Thus, I can finally move forward with the plan, which is to add a passel of floating-point opcodes to the Glulx spec.
numtof – convert an int to a float of equal value (or as close as possible)
ftonum – convert a float to the nearest integer
As you have gathered already, integer values do not match float values. You can’t feed floats to the regular arithmetic opcodes and expect to get meaningful answers. You’ll have to convert back and forth, using ftonum and numtof.
(Or allow the language to do it for you. I7’s type system will eventually encompass floats and do all the conversion for you magically.)
Clearly we need a bunch of float-specific opcodes, and here they are:
fadd, fsub, fmul, fdiv, fmod – ordinary arithmetic
ceil, floor – round up or down, to the nearest integral value (but return that as a float; this does not convert to int format)
sqrt, exp, pow, log – old math warhorses
sin, cos, tan, acos, asin, atan, atan2 – trigonometry
jflt, jflte, jfgt, jfgte – jump if less than (etc)
jfeq – jump if equal to. This takes three arguments (X, Y, epsilon) and tests whether X and Y are within epsilon of each other. I suspect this will be more useful than straight-up equality, but you can always pass epsilon=0.0.
jfne – jump if not equal to; same gimmick.
jisnan – jump if the value is Not A Number. NaN is a magical value that results from certain illegal operations, like 0/0.
jisinf – jump if the value is infinity (or negative infinity). Yes, the floating-point spec lets you compute with infinities. 1/0 is infinity, -1/0 is negative infinity. Roll with it.
Opcodes that I’m not including:
fneg – it happens to be true that the sign bit of float values is 0x80000000, just like for integers. So the regular neg opcode will work here.
fabs – similarly, you can get the absolute value by squashing the top bit.
sinh, cosh, tanh – does anybody care? Also, Javascript’s math library doesn’t have them.
Opcodes that I’m not sure about, feel free to make an argument for or against them:
fhypot (pythagorean distance) – easy enough to synthesize, but maybe it’s common enough to use
jfz – jump if (exactly) zero. This would be identical to jz except for NaN values and negative zero. Yeah, there’s a negative zero. Anyhow, you can use jfeq for this, but there’s an integer jz so why not this one?
isfinite, isnormal – these exist in the C library so maybe somebody wants them.
log10 – ditto.
streamfloat – print a float value. I don’t much want to do this because I’d have to define the formatting in a stable way (across libc and Javascript), and is that even possible? But leaving it out sucks too. Should there be some format-control arguments?
Other notes:
The low-level math libraries on some computers can return NaN values with extra information encoded in them. IEEE-754 can represent these, but Glulx will not. (Because, first, there’s no C standard for getting at them. And second, Javascript can’t get at them at all.)
Float math will be distinctly slower than int math. This is not because of the low-level operations (which are trivial), but because the interpreter has to keep converting back and forth between IEEE-encoded floats and native floats. A C interpreter can usually do this fast (because most computers use IEEE-encoded floats natively) but Javascript has to go through a whole bit-fiddling process. And of course Javascript is where the speed concerns are.
I have not yet done enough testing to know whether float math will produce bit-identical results between Javascript and C interpreters. I suspect it won’t.
When will I get to this? Not before Quixe is out the door, that’s for sure. The implementation work is not too bad, but there will have to be a cyclopean pile of unit tests before I trust it.
I’ll post a draft Glulx spec update in the next few weeks, I hope, but it won’t be definitive until I have the code all working and tested.
Any comments on any of this?