Discussion:
ISO WriteReal() and StrToReal()
(too old to reply)
tbreeden
2010-08-23 20:21:12 UTC
Permalink
I'm trying to figure out what the ISO Std Library procs WriteReal()
and StrToReal() should output for various inputs.

Anyone thought about this?

I've stopped looking at various implementations and gone back to the
ISO document. There is not much more text there than the comment that
appears in the Definition file:

PROCEDURE RealToStr(real : REAL; VAR str : ARRAY OF CHAR);
(* Converts the value of real as RealToFixed if the sign and
magnitude
can be shown within the capacity of str, or otherwise as
RealToFloat,
and copies the possibly truncated result to str. The number of
places
or significant digits depend on the capacity of str. *)

In particular, "magnitude" is not defined in the text, but I think it
refers to the whole number part of the absolute value of the real.
That leads me to believe that WriteReal() is most appropriate for
numbers that you don't care how small they get if they are really
small, but you do care to know how big they get.

Unfortunately, unlike for RealToFixed() and RealToFloat(), the ISO
Standard neglected to put in a nice little table with example inputs
and outputs. :(

Looking at the VDM-SL definition, it seems that the RealToFixed() (or
WriteFixed()) is used only if the characters in the string
representation of that whole number part (plus 1 if a negative sign is
needed) are less than or equal to the available output character slots
(width). ie, the VDM code first counts the characters in the number
rounded to the nearest 0.5

This also implies that any number of absolute value less than 1.0 will
surely be output as WriteFixed()

So, I would expect these outputs:

r := 3.14159265358979;
WriteReal(r, 10); WriteLn; (* 3.14159265 *)

r := 314159.265358979;
WriteReal(r, 10); WriteLn; (* 314159.265 *)

r := 31415926535.8979;
WriteReal(r, 10); WriteLn; (* 3.14159E10 *)

r := 0.314159265358979;
WriteReal(r, 10); WriteLn; (* 0.31415926 *)

r := 0.0314159265358979;
WriteReal(r, 10); WriteLn; (* 0.03141592 *)

r := 0.00000314159265358979;
WriteReal(r, 10); WriteLn; (* 0.00000314 *)

r := 0.000000000314159265358979;
WriteReal(r, 10); WriteLn; (* 0.00000000 *)

This does not seem to be the way it is usually(?) implemented (eg,
StonyBrook). Rather it looks as if the implementation always uses
WriteFloat() format for any number whose absolute value is < 1.0

Have I missed something?

Thanks,

Tom
Martin Brown
2010-08-23 21:48:01 UTC
Permalink
Post by tbreeden
I'm trying to figure out what the ISO Std Library procs WriteReal()
and StrToReal() should output for various inputs.
Anyone thought about this?
I've stopped looking at various implementations and gone back to the
ISO document. There is not much more text there than the comment that
PROCEDURE RealToStr(real : REAL; VAR str : ARRAY OF CHAR);
(* Converts the value of real as RealToFixed if the sign and
magnitude
can be shown within the capacity of str, or otherwise as
RealToFloat,
and copies the possibly truncated result to str. The number of
places
or significant digits depend on the capacity of str. *)
Some interesting stress tests would be
2.3456789E-308
2.3456789E+308

And a destination string length of 6, 7 and 8 characters. I don't like
the sound of possibly truncated representations of reals as strings. I
would much rather have a bunch of ugly looking asterisks than the wrong
number printed out without any warning.
Post by tbreeden
r := 0.0314159265358979;
WriteReal(r, 10); WriteLn; (* 0.03141592 *)
r := 0.00000314159265358979;
WriteReal(r, 10); WriteLn; (* 0.00000314 *)
r := 0.000000000314159265358979;
WriteReal(r, 10); WriteLn; (* 0.00000000 *)
In an ideal world you might hope that it would switch to
3.14E-010
here.
Post by tbreeden
This does not seem to be the way it is usually(?) implemented (eg,
StonyBrook). Rather it looks as if the implementation always uses
WriteFloat() format for any number whose absolute value is< 1.0
Have I missed something?
Dunno. I don't have a copy of the ISO std.

Regards,
Martin Brown
aaaaaaaaaaaaaaaaaaaaaaaaaa
2010-08-24 10:31:17 UTC
Permalink
Post by tbreeden
I'm trying to figure out what the ISO Std Library procs WriteReal()
and StrToReal() should output for various inputs.
Just make a loop that prints out several magnitudes (i.e increasing
exponents) and then decide to ditch ISO.

ISO is not synunym to 'good'. ISO justmeans a bunch of people have
agreed in conensus that this version is least problematic to all.

As we said at a major japanese company that thrived on consensus :
consensus kills creativity. And quality.
Post by tbreeden
r := 0.000000000314159265358979;
WriteReal(r, 10); WriteLn; (* 0.00000000 *)
RIDICULOUS and dangerous. If this is characteristic for ISO I get one
more reason for keeping as far away from ANY iso thing as possible.
For Modula-2 there is only 1 standard: PIMmyness. PIM3 or PIM4 is open
for debate. ISO is just there to satisfy some civil servant who wants
to control the world, including free software.
Post by tbreeden
Have I missed something?
Definitely. ISO and DIN are nice for foodstuff and the tolerances of
lathes. For Modula-2 only PIMmyness counts.
tbreeden
2010-08-24 13:18:40 UTC
Permalink
Post by Martin Brown
In an ideal world you might hope that it would switch to
3.14E-010
here.
RIDICULOUS and dangerous. If this is characteristic for ISO I get one
more reason for keeping as far away from ANY iso thing as possible.
For Modula-2 there is only 1 standard: PIMmyness. PIM3 or PIM4 is open
for debate. ISO is just there to satisfy some civil servant who wants
to control the world, including free software.
Let me clarify what I was hoping I could get from this thread. I'm
coming from a position where I think it is a wirthy thing for people
using a common module to understand the behaviour of its procedures.

I've found a procedure in a common module that seems to be well
defined, but I am not sure that I understand the definition correctly,
since well regarded implementations don't seem to agree with my
understanding.

e.g., Rick Sutcliffe's on-line M2 Textbook gives this example:
WriteReal (pi/10000.0, 10);
produces the output
3.1415E-04

when it seems to me that from the definition in the standard it should
produce the output
0.00031415

Sorry, without the full specification it is kind of hard for people to
respond, so I'll assume that this falls under "fair-user" and quote
the VDM-SL definition of realstr:

Tom

-----------------------------------------------------------------------------------------------

realstr : R x N1 -> Char*

realstr (value, width)
let round : N be st abs (round - abs value) <= 0.5 in
let whole : Char* be st numeric-value (whole) = round in
let needs = if value < 0 then len whole + 1 else len whole in
if width >= needs
then let place = width-needs-l in
fixedstr (value, place)
else let mantissa : R, exp : N be st mantissa x 10^exp = abs value
AND
mantissa < 10.0 AND mantissa >= 0.0 in
let l1 = if value < 0 then 2 else 1 in
let sexp : Char* be st numeric-value (sexp) = abs exp in
let l2 = if exp = 0 then 0
elseif exp > 0 then len sexp else len sexp + 1 in
let figs = if width - I1 - Z2 > 1 then width - 11 - Z2 - 1 else 1
in
floatstr (value, figs)
Fruttenboel
2010-08-24 19:00:50 UTC
Permalink
This is how the ACK does things:

PROCEDURE RealToString(r: REAL;
width, digits: INTEGER;
VAR str: ARRAY OF CHAR;
VAR ok: BOOLEAN);
(* Convert real number "r" to string "str", either in fixed-point or
exponent notation.
"digits" is the number digits to the right of the decimal point,
"width" is the maximum width of the notation.
If digits < 0, exponent notation is used, otherwise fixed-point.
If fewer than "width" characters are needed, leading blanks are
inserted.
If the representation does not fit in "width", then ok is set to
FALSE.
*)

It may not be ISO but it is CLEAR and PREDICTABLE how a number will be
formatted and displayed.

This is how Mocka does things:

PROCEDURE WriteReal (x : REAL; n : CARDINAL; k : INTEGER);

(* Convert the real 'x' into external representation and *)
(* write it onto std output. Field width is at least 'n'. *)
(* If k > 0 use k decimal places. *)
(* If k = 0 write x as integer. *)
(* If k < 0 use scientific notation. *)

Again: not ISO and very predictable. If I want to print a real as an
integer, I will use the ENTIER function.

If the printing format is unpredictable, better stay away from that
method.

At least, that's my opinion.

Loading...