Mirsad Todorovac wrote:
Please read without prejudice!
What would you think of the following: we all know about various bitsizes Integer and Cardinal types.
What I've seen was a "customized" real type. Imagine you have to store lots of data for GSM-encoding, or some similar measurement purpose. Lots of bits are wasted, as they don't correspond to accurate digits of measurement. I.e. on a weather station that has only an occassional link to a satellite.
For example, let's suppose we have lots of data that that we could express as reals in 16-bit precision, and all fit between -0.5 and 0.5 (for example, but standard can be defined in different way):
type MyReal = Real attribute (Exponent = 0, Mantissa = 16);
GSMReal = Real attribute (Exponent = 8, Mantissa = 8);
The latter could represent a number with same range like IEEE single precision float, just with only 2 accurate digits.
or even TEMPReal = Real attribute (ExponentRange = 0..15, Mantisa = 4);
for keeping the temperature in one byte from range of 0.0625 K to 30720 K (where precision is not that much important as the value on the logarithmic scale ...)
The compiler could use hardware floating point when it's faster than emulation with less bits of precision, then round/truncate when storing back into memory/variable.
This is just a tip, not a real syntax or semantics proposal.
Something like this was suggested, referring to the Fortran feature `SELECTED_REAL_KIND'. I don't know Fortran, though, so I don't know exactly how it works.
Anyway, as you're certainly aware, the main problem is to implement all this (whereas the syntax, e.g. as using attributes, should be no big problem). Basically, you need a complete software floating point emulation with arbitrary precision/range of which parts have to be in the compiler, other parts can be done in the RTS, and the interfaces between them have to be defined and implemented.
Then don't underestimate the (implicit, I suppose) conversions required between those and standard real types (and even from integer). If I think of the plans for various string types, that's a main issue there.
This also raises the issue how to handle real constants. To avoid loss of precision, they might have to be kept in such a format in the compiler (which means that you need two versions of this emulation, one at compile-time, one at run-time).
The same is true if you want compile-time optimizations, but they will probably require even more work since the existing optimizations for real types will probably have to be copied or in part rewritten for the new types.
If you want to handle them in I/O, you also need a new mechanism(*).
Now, an alternative would be to use GMP types. They're a little different since they can determine the precision at runtime. This is more flexible, but requires dynamic memory allocation, which is also more overhead (so they're suitable when you need big precision, not for those examples above where you want reduced precision and storage requirements).
Another disadvantage of them is that they require routine calls. It is possible to wrap some of them into user-defined operators, but it only goes so far. I did that in http://gnu-pascal.de/contrib/frank/gmpop.inc, but it has some limitations. (There's a longish comment in the file that describes the details.) The main problem is that they need explicit initialization and finalization routine calls, and GPC doesn't yet support those. (It's a planned feature, but especially for finalizers not exactly trivial, but I may do it sometime ...)
Another idea, for your first example, would be to use a fixed-point representation (indeed, I'd recommend that since it would probably be the cheapest (at runtime) solution). Just use a 16 bit integer and do the operations on it with appropriate scaling.
In fact, you can also use operators for this (their implementation is mostly as boring as in gmpop.inc, but without the problems of initialization/finalization). If you wrap the integer in a record (or an array of size 1), you can prevent it from being accidentally used as an integer value. This way, I think, only conversions from integer or real to the fixed point type will need an explicit function call, and I/O needs to be dealt with(*), anything else (including comparisons) will work with operators.
Of course, something like this can also be done with any user-space implemented floating point emulation (perhaps using schemata for the varying exponent/mantissa size, though you have the overhead of the discriminants being stored in the schemata). It might be interesting to see how far one gets this way. One limitation will, also here, be the lack of automatic conversions. (This refers to the recent discussion of "type-cast" operators or something like this which is another can of worms I think ...)
(*) There was another idea to allow for user-defined I/O operators for arbitrary types, something like this:
operator Write (var f: Text; a: MyType); [...]
Which would allow:
var Foo: MyType;
begin WriteLn ('Hello ', Foo, 42) end.
This might actually not be too difficult to implement ...
Bottom line: I think the suggested feature would be a *major* effort to implement. I'm not sure if we should add it to the compiler (it's already so complex) if a user-space solution, even perhaps with some small drawbacks, is possible ...
Frank