Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

f.rdp in gforth

237 views
Skip to first unread message

krishna...@ccreweb.org

unread,
Jul 23, 2017, 11:40:00 PM7/23/17
to
For justified fixed point output of a floating point
number, I considered Gforth's non-standard word, F.RDP,
which has the stack diagram

( nr nd np -- ) ( F: r -- )

where r is the double-precision floating point number,
nr is the total width of the output, nd is the number
of digits after the decimal point, an np is the minimum
number of significant digits.

This seems over-specified to me. In particular I do not
understand the reason for the np argument. Wouldn't a
useful, justified fixed-point output should just need
the width and number of decimal place parameters, nr
and nd? Also F.RDP behaves in a way that is somewhat
counter-intuitive to me. If I specify a fixed number
of decimal places, nd, in the output, I don't expect
the output to be followed by trailing zeros, implying
that I have significant decimal places beyond nd places,
e.g.

3.141527e 12 6 10 f.rdp 3.14152700E0 ok

Why are there two zeros after the specified number of
decimal places, and why is there a trailing E0 (I
don't want scientific notation!). Now, if I do

3.141527e 12 6 7 f.rdp 3.141527 ok

that's the output I want, but I have to tell f.rdp the
total number of significant digits in advance to get
fixed point output without implied significant digits
to the right of the decimal point. This behavior is
not useful for fixed point output in the general case.

I implement a justified, fixed-point output with just
the nr and nd parameters, which guarantees that I have
fixed point output with only the specified number of
digits trailing the decimal point. The field width, nr,
can then be selected to be nd plus 1 (for the decimal
point) plus the number of digits in the largest expected
integer portion of the number, plus 1 for handling the
sign of the number:

\ Convert r to a formatted fixed point string with
\ n decimal places
: f>fpstring ( r n -- a u )
1 swap dup >r 0 ?do 10 * loop
s>f f* fround f>d dup -rot dabs
<# r> 0 ?do # loop [char] . hold #s rot sign #> ;

\ Print an fp number as a fixed point string with
\ n decimal places, right-justified in a field of width, w
: fprint ( r n w -- )
>r f>fpstring r> over -
dup 0> IF spaces ELSE drop THEN type ;

The same example above, using fprint instead of f.rdp, are
given below (note the order of nr and nd are reversed):

3.141527e 6 12 fprint
3.141527 ok

In the above example, the total field width is 12, and
the number of decimal places to be output is 6. I am
guaranteed to be able to represent the number of
significant digits after the decimal point without the
word inserting extra digits. What happens when the
integer portion exceeds the field width (12 in this
example)? Let's check:

1234567.123456e 6 12 fprint
1234567.123456 ok

Here the entire number is output, though it exceeds the
field width by 2 characters. This is reasonable, since,
for fixed point output, we are concerned primarily with
not changing the number of significant digits after the
decimal point *and* that the number not be misrepresented
on output. Similarly with the negative version of the
number:

-1234567.123456e 6 12 fprint
-1234567.123456 ok

Therefore, we break the field width and justified
formatting to not misrepresent the number. However,
the number of decimal places specified for the
output is inviolate. In my experience this type of
behavior is much more useful than the behavior of
F.RDP; however, I may be missing some particular
use case.

Krishna






hughag...@gmail.com

unread,
Jul 24, 2017, 12:21:25 AM7/24/17
to
I have <SCIENTIFIC> in the novice-package:

: <scientific> { prec engineering? | sgn exp -- adr cnt } \ float: n --
...

10 constant max-prec \ 11 works sometimes, but fails if the most significant digit is large. 10 always works.

: scientific ( -- adr cnt ) \ float: n --
precision false <scientific> ;

: max-scientific ( -- adr cnt ) \ float: n --
max-prec false <scientific> ;

: engineering ( -- adr cnt ) \ float: n --
precision true <scientific> ;

: max-engineering ( -- adr cnt ) \ float: n --
max-prec true <scientific> ;

2000000001 constant eng-lim \ must be a positive integer
\ In <ENG> any float >= the lim goes to ENGINEERING and otherwise is done without an 'e'

: <eng> ( -- adr cnt lim ) \ float: n --
...
: eng ( -- adr cnt ) \ float: n --
eng-lim <eng> ;

This has already been discussed at length here:
https://groups.google.com/forum/#!topic/comp.lang.forth/uGAKvs8baQk%5B1-25%5D

This is a quote from that thread:
On Friday, December 16, 2016 at 7:26:12 PM UTC-7, hughag...@gmail.com wrote:
> Here are some tests:
> ----------------------------------------------------------------------------------
> 2000000000.0001e ok F:-1
> eng type 2,000,000,000.0001 ok
> 2000000001.0001e ok F:-1
> eng type 2e9 ok
> 2000000000.000123456789e ok F:-1
> eng type 7,751,640.03949188 ok \ this is a bug in VFX --- F. doesn't work either
> 2000000000.0001e ok F:-1
> eng type 2,000,000,000.0001 ok
> 2000000.0001234567e ok F:-1
> eng type 2,000,000.00012346 ok
> 0.0e ok F:-1
> eng type 0 ok
> -0.0e ok F:-1
> eng type 0 ok
> -0.0001e ok F:-1
> eng type -100e-6 ok
>
> ----------------------------------------------------------------------------------
>
> Notice that I found a bug in VFX during my testing. My Forth is pretty good --- when problems occur, my first thought is that there is a bug in the compiler rather than in my own code --- most of the time, this is the case.
>
> Andrew Haley should be pleased that I wrote this code: "eschewing highfalutin theories in favour of what it takes to get real work done." LOL

Anton Ertl

unread,
Jul 24, 2017, 5:33:09 AM7/24/17
to
krishna...@ccreweb.org writes:
>For justified fixed point output of a floating point
>number, I considered Gforth's non-standard word, F.RDP,
>which has the stack diagram
>
> ( nr nd np -- ) ( F: r -- )
>
>where r is the double-precision floating point number,
>nr is the total width of the output, nd is the number
>of digits after the decimal point, an np is the minimum
>number of significant digits.
>
>This seems over-specified to me. In particular I do not
>understand the reason for the np argument. Wouldn't a
>useful, justified fixed-point output should just need
>the width and number of decimal place parameters, nr
>and nd?

Maybe, but F.RDP is not fixed-point notation only. It prefers
fixed-point, but if that does not satisfy the constraints, switches to
exponential notation, and if that does not fit, either, it switches to
stars. That's specified in the documentation, which also contains
recommendations:

|Print float rf formatted. The total width of the output is nr. For
|fixed-point notation, the number of digits after the decimal point is
|+nd and the minimum number of significant digits is np. Set-precision
|has no effect on f.rdp. Fixed-point notation is used if the number of
|siginicant digits would be at least np and if the number of digits
|before the decimal point would fit. If fixed-point notation is not
|used, exponential notation is used, and if that does not fit,
|asterisks are printed. We recommend using nr>=7 to avoid the risk of
|numbers not fitting at all. We recommend nr>=np+5 to avoid cases where
|f.rdp switches to exponential notation because fixed-point notation
|would have too few significant digits, yet exponential notation offers
|fewer significant digits. We recommend nr>=nd+2, if you want to have
|fixed-point notation for some numbers. We recommend np>nr, if you want
|to have exponential notation for all numbers.

> Also F.RDP behaves in a way that is somewhat
>counter-intuitive to me. If I specify a fixed number
>of decimal places, nd, in the output, I don't expect
>the output to be followed by trailing zeros, implying
>that I have significant decimal places beyond nd places,
>e.g.
>
>3.141527e 12 6 10 f.rdp 3.14152700E0 ok
>
>Why are there two zeros after the specified number of
>decimal places, and why is there a trailing E0 (I
>don't want scientific notation!).

The trailing zeros are there because it uses exponential notation. It
uses exponential notation, because you asked for >=10 significant
digits, and fixed-point notation with nd=6 would have given you only
7. If you want fixed-point notation, better use np<=nd.

> Now, if I do
>
>3.141527e 12 6 7 f.rdp 3.141527 ok
>
>that's the output I want, but I have to tell f.rdp the
>total number of significant digits in advance to get
>fixed point output without implied significant digits
>to the right of the decimal point.

No, you also get that output for any 0<=np<=7.

>-1234567.123456e 6 12 fprint
>-1234567.123456 ok
>
>Therefore, we break the field width and justified
>formatting to not misrepresent the number. However,
>the number of decimal places specified for the
>output is inviolate. In my experience this type of
>behavior is much more useful than the behavior of
>F.RDP; however, I may be missing some particular
>use case.

If you print tables with numbers with significant differences in
magnitude, with, say 7 significant digits, the number of digits after
the decimal point is not that important, but you still want to use
fixed point notation (and with a fixed point) for cases where that
notation fits in the field width. That's the use case that F.RDP was
designed for. And tables become much less useful if the columns don't
align.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2017: http://euro.theforth.net/

krishna...@ccreweb.org

unread,
Jul 24, 2017, 11:24:44 AM7/24/17
to
On Monday, July 24, 2017 at 4:33:09 AM UTC-5, Anton Ertl wrote:
> krishna.myneni@...org writes:
> >For justified fixed point output of a floating point
> >number, I considered Gforth's non-standard word, F.RDP,
> >which has the stack diagram
> >
> > ( nr nd np -- ) ( F: r -- )
> >
> >where r is the double-precision floating point number,
> >nr is the total width of the output, nd is the number
> >of digits after the decimal point, an np is the minimum
> >number of significant digits.
> >
> >This seems over-specified to me. In particular I do not
> >understand the reason for the np argument. Wouldn't a
> >useful, justified fixed-point output should just need
> >the width and number of decimal place parameters, nr
> >and nd?
>
> Maybe, but F.RDP is not fixed-point notation only. It prefers
> fixed-point, but if that does not satisfy the constraints, switches to
> exponential notation, and if that does not fit, either, it switches to
> stars. That's specified in the documentation, which also contains
> recommendations:
>
...
> >
> >3.141527e 12 6 10 f.rdp 3.14152700E0 ok
> >
> >Why are there two zeros after the specified number of
> >decimal places, ...
>
> The trailing zeros are there because it uses exponential notation. It
> uses exponential notation, because you asked for >=10 significant
> digits, and fixed-point notation with nd=6 would have given you only
> 7. If you want fixed-point notation, better use np<=nd.
>
> > Now, if I do
> >
> >3.141527e 12 6 7 f.rdp 3.141527 ok
> >
> >that's the output I want, but I have to tell f.rdp the
> >total number of significant digits in advance to get
> >fixed point output ...
>
> No, you also get that output for any 0<=np<=7.
>

Test:

3.141527e 12 6 0 f.rdp 3.141527 ok

Ok. That's useful to know. So, if I want to ensure that the
number of digits after the decimal point is consistent, when
F.RDP chooses to uses fixed point format), I can use zero for
the "np" parameter. But, there is no way to ensure F.RDP will
always use fixed point format for output, and the behavior of
F.RDP is too complicated to be easily predicted. I will say
more about the typical case needs for formatted floating
point output below.


> >-1234567.123456e 6 12 fprint
> >-1234567.123456 ok
> >
> >Therefore, we break the field width and justified
> >formatting to not misrepresent the number. However,
> >the number of decimal places specified for the
> >output is inviolate. In my experience this type of
> >behavior is much more useful than the behavior of
> >F.RDP; however, I may be missing some particular
> >use case.
>
> If you print tables with numbers with significant differences in
> magnitude, with, say 7 significant digits, the number of digits after
> the decimal point is not that important, but you still want to use
> fixed point notation (and with a fixed point) for cases where that
> notation fits in the field width. That's the use case that F.RDP was
> designed for. And tables become much less useful if the columns don't align.

Column-aligned tables of floating point numbers are the reason
for my discussion. I can readily identify three common use
cases. In all cases, it is useful to have alignment of the
numbers on the decimal point, for human readability and
comprehension:

case 1)
The output in a column should display all the numbers
with a fixed number of significant digits.

Scientific/engineering notation is best used in this case,
but will still require justification of the string
representation of the output of FS. (in combination with
SET-PRECISION) within a fixed field width, to align the
numbers to the decimal point, e.g. a column of numbers
with 6 significant digits in a field of width 14.
Alignment with the decimal point can be achieved simply
by right justifying the numbers in the field if the
string representation uses a fixed with exponent field
which always includes the sign; otherwise alignment with
the decimal point takes a little more work:

12345678901234
--------------
3.14159E+000
6.62607E-034
-1.41421E+001

case 2)
The column output should display a fixed point format
with a constant number of decimal places (in contrast
with a constant number of significant digits, as in
case 1). The number of of significant digits may vary
for each number, e.g.

12345678901234
--------------
21.3657
-1.0021
1020.7448
-15384.0931

Once again, we use a field width of 14. Now, the number
of decimal places is constant, but the number of
significant digits vary from row to row. The numbers are
all aligned to the decimal point, which is very easy to
do since right justification of the output string within
the field will produce the appropriate alignment.

case 3)
The column output is desired in fixed point format within
a constant field width, but with neither a constant number
of decimal places nor a constant number of significant
digits. Alignment should be to the decimal point.

12345678901234
--------------
21.3657206
1.0021
-516.7
65532.

The range of numbers in this last example is exaggerated
from the typical use cases I've encountered, but it is
common to need this type of formatting within a fixed-width
column. For this case, the output word does need three
parameters: the field width, the number of decimal places,
and the offset (column position) of the decimal point.

The FPRINT word, which is not a name that is suitably
descriptive of what the word does, only handles case 2).
A more suitable word name would be something like F.RD , in
analogy with the x.R words for single and double integers.
I think it is best for each of the three cases to have
their own words, without a single word deciding the best
output format. Have I missed any other common use cases?


Krishna





Anton Ertl

unread,
Jul 24, 2017, 6:24:05 PM7/24/17
to
krishna...@ccreweb.org writes:
>Ok. That's useful to know. So, if I want to ensure that the
>number of digits after the decimal point is consistent, when
>F.RDP chooses to uses fixed point format), I can use zero for
>the "np" parameter. But, there is no way to ensure F.RDP will
>always use fixed point format for output, and the behavior of
>F.RDP is too complicated to be easily predicted.

It's pretty easy: If you want fixed point and hardly care care about
significant digits, use

: f.rd 1 f.rdp ;

and you will get fixed point whenever fixed point makes some sense
(i.e., when the result fits, and as long as there is at least 1
significant digit. E.g., you will get fixed point notation for

1.23e4 12 6 1 f.rdp \ outputs "12300.000000"
1.23e-6 12 6 1 f.rdp \ outputs " 0.000001"

but gives exponential notation for

1.23e5 12 6 1 f.rdp \ outputs "1.23000000E5"
1.23e-7 12 6 1 f.rdp \ outputs "1.2300000E-7"

What would you prefer instead of exponential notation in these cases?

If you always want exponential notation, use np>nr, as recommended by
the documentation.

So it's easy to predict the behaviour, you just have to invest the
time to think through the the parameters.

>Column-aligned tables of floating point numbers are the reason
>for my discussion. I can readily identify three common use
>cases. In all cases, it is useful to have alignment of the
>numbers on the decimal point, for human readability and
>comprehension:
>
>case 1)
>The output in a column should display all the numbers
>with a fixed number of significant digits.
>
>Scientific/engineering notation is best used in this case,
>but will still require justification of the string
>representation of the output of FS. (in combination with
>SET-PRECISION) within a fixed field width, to align the
>numbers to the decimal point, e.g. a column of numbers
>with 6 significant digits in a field of width 14.
>Alignment with the decimal point can be achieved simply
>by right justifying the numbers in the field if the
>string representation uses a fixed with exponent field
>which always includes the sign; otherwise alignment with
>the decimal point takes a little more work:
>
>12345678901234
>--------------
> 3.14159E+000
> 6.62607E-034
> -1.41421E+001

I don't find that very useful. It's hard to see how big numbers are.
But anyway, if you want something like this, use 14 14 15 f.rdp, and
you get

3.1415926536E0

F.RDP prefers showing mantissa digits over the kind of fixed
exponential format that you outline above, but does that hurt
readability more than exponential notation itself? I don't think so.

>case 2)
>The column output should display a fixed point format
>with a constant number of decimal places (in contrast
>with a constant number of significant digits, as in
>case 1). The number of of significant digits may vary
>for each number, e.g.
>
>12345678901234
>--------------
> 21.3657
> -1.0021
> 1020.7448
> -15384.0931
>
>Once again, we use a field width of 14. Now, the number
>of decimal places is constant, but the number of
>significant digits vary from row to row. The numbers are
>all aligned to the decimal point, which is very easy to
>do since right justification of the output string within
>the field will produce the appropriate alignment.

That's pretty much what the F.RD above gives you, if you limit
yourself to numbers that fit fixed-point notation. However, what do
you do if you have to print 1.23456e20 or 1.23456e-10?

>case 3)
>The column output is desired in fixed point format within
>a constant field width, but with neither a constant number
>of decimal places nor a constant number of significant
>digits. Alignment should be to the decimal point.
>
>12345678901234
>--------------
> 21.3657206
> 1.0021
> -516.7
> 65532.
>
>The range of numbers in this last example is exaggerated
>from the typical use cases I've encountered, but it is
>common to need this type of formatting within a fixed-width
>column.

Common? Not really. I cannot remember ever seeing this before.

>For this case, the output word does need three
>parameters: the field width, the number of decimal places,
>and the offset (column position) of the decimal point.

Sounds like nr, np, and nd to me (F.RDP does not produce output
like this).

krishna...@ccreweb.org

unread,
Jul 24, 2017, 10:49:34 PM7/24/17
to
On Monday, July 24, 2017 at 5:24:05 PM UTC-5, Anton Ertl wrote:
> krishna...org writes:
...
> >... But, there is no way to ensure F.RDP will
> >always use fixed point format for output, and the behavior of
> >F.RDP is too complicated to be easily predicted.
>
> It's pretty easy: If you want fixed point and hardly care care about
> significant digits, use
>
> : f.rd 1 f.rdp ;
>

F.RDP can have its uses, but, in practice, it is not a
convenient choice for formatted floating point output.
The point is not that one does not care about significant
digits for fixed point output, but that the number of
significant digits varies for like-kind of numbers in a
column. For example, calculations with a well defined
absolute uncertainty of some quantity as a function of
an independent variable may be made to an error tolerance,
e.g. +/- 0.001 meters -- in such a case, we want to
display the column of numbers (in units of meters) to
3 decimal places. However, the integer portion of the
number may vary from zero to 10 meters. Then, the number
of significant digits varies from 3 to 5, in this case.
F.RDP will not guarantee that your output stays in
fixed point format.

> and you will get fixed point whenever fixed point makes some sense
> (i.e., when the result fits, and as long as there is at least 1
> significant digit. E.g., you will get fixed point notation for
>
> 1.23e4 12 6 1 f.rdp \ outputs "12300.000000"
> 1.23e-6 12 6 1 f.rdp \ outputs " 0.000001"
>

The above is ok, when you want fixed point output and you
specify 6 decimal places.

> but gives exponential notation for
>
> 1.23e5 12 6 1 f.rdp \ outputs "1.23000000E5"
> 1.23e-7 12 6 1 f.rdp \ outputs "1.2300000E-7"
>
> What would you prefer instead of exponential notation in these cases?
>
This is not ok, because I want fixed point format in
my column of numbers. The column is not easily readable
if the format changes, even if the field width is the
same. My preference is that it stays in fixed point format
with the specified number of decimal places, e.g.

1.23e5 12 6 1 f.rdp \ outputs "123000.000000"
1.23e-7 12 6 1 f.rdp \ outputs " 0.000000"

Note that the first number overflows the field width,
and this is acceptable. It means the programmer did
not estimate his required field width correctly, and
he can go back and fix his field width if he wants
fixed point output. This would be entirely appropriate
if the tolerance on the numbers was ~1e-6. If, however,
it is important to express the column of numbers to
a fixed number of significant digits, then the programmer
should have chosen scientific notation as the output
format.

> If you always want exponential notation, use np>nr, as recommended by
> the documentation.
>
> So it's easy to predict the behaviour, you just have to invest the
> time to think through the the parameters.
>

I feel that F.RDP tries to do too many things. It suffers
from the same problem as F~ in ANS-Forth.
When you have a range that spans many orders of magnitude,
(35 in this case) there is simply no useful way of preparing
fixed width column output to represent a fixed number of
significant digits other than to use scientific or engineering
notation.

> But anyway, if you want something like this, use 14 14 15 f.rdp, and
> you get
>
> 3.1415926536E0
>
> F.RDP prefers showing mantissa digits over the kind of fixed
> exponential format that you outline above, but does that hurt
> readability more than exponential notation itself? I don't think so.

If you set np>nr, both the first and second arguments to
F.RDP are meaningless -- the output is determined only
by the number of significant digits, and the sign of the
number. This does not make for a nicely aligned
justified column, unless you assume the sign to be
uniform.


>
> >case 2)
> >The column output should display a fixed point format
> >with a constant number of decimal places (in contrast
> >with a constant number of significant digits, as in
> >case 1). The number of of significant digits may vary
> >for each number, e.g.
> >
> >12345678901234
> >--------------
> > 21.3657
> > -1.0021
> > 1020.7448
> > -15384.0931
> >
> >Once again, we use a field width of 14. Now, the number
> >of decimal places is constant, but the number of
> >significant digits vary from row to row. The numbers are
> >all aligned to the decimal point, which is very easy to
> >do since right justification of the output string within
> >the field will produce the appropriate alignment.
>
> That's pretty much what the F.RD above gives you, if you limit
> yourself to numbers that fit fixed-point notation. However, what do
> you do if you have to print 1.23456e20 or 1.23456e-10?
>

I assume you meant F.RDP in the sentence above.
If you have to print numbers over such a wide range of
magnitude as 1e20 and 1e-10, you should choose case 1),
i.e. use scientific notation for the entire column, not
fixed point output. This is a programmer decision, not one
which should be made by the output word. The fixed point
output word should do what it's told to do.


> >case 3)
> >The column output is desired in fixed point format within
> >a constant field width, but with neither a constant number
> >of decimal places nor a constant number of significant
> >digits. Alignment should be to the decimal point.
> >
> >12345678901234
> >--------------
> > 21.3657206
> > 1.0021
> > -516.7
> > 65532.
> >
> >The range of numbers in this last example is exaggerated
> >from the typical use cases I've encountered, but it is
> >common to need this type of formatting within a fixed-width
> >column.
>
> Common? Not really. I cannot remember ever seeing this before.
>

It is required when a column of numbers aren't like-kinds
of quantities, for example, and need different tolerances
(different number of decimal places) and different number
of significant digits (scale of numbers). Even for like-kind
of quantities it is sometimes needed. For example, consider
measurements of various lengths describing an object, which
may range from meter to cm scale, each measured to a
different tolerance, but all expressed in the same units.
Another instance in which the number of decimal places and
the number of significant digits may change is when a
measurement instrument's scale changes.

> >For this case, the output word does need three
> >parameters: the field width, the number of decimal places,
> >and the offset (column position) of the decimal point.
>
> Sounds like nr, np, and nd to me (F.RDP does not produce output
> like this).
>

Yes, almost, but the problem with specifying nr, np, and nd
is that there is no way to align to the decimal point. However,
this case is perhaps a special case, and will require special
word(s) to handle.

Krishna

minf...@arcor.de

unread,
Jul 25, 2017, 1:35:43 AM7/25/17
to
Am Dienstag, 25. Juli 2017 04:49:34 UTC+2 schrieb krishna...@ccreweb.org:

> Yes, almost, but the problem with specifying nr, np, and nd
> is that there is no way to align to the decimal point. However,
> this case is perhaps a special case, and will require special
> word(s) to handle.
>
> Krishna

That's what REPRESENT is for: a building block from which application-specific
formatted output is easy.

Anton Ertl

unread,
Jul 25, 2017, 6:33:34 AM7/25/17
to
minf...@arcor.de writes:
>That's what REPRESENT is for: a building block from which application-specific
>formatted output is easy.

Unfortunately, it turns out not to be easy. There are the following
issues:

* REPRESENT is very simular to ecvt(), but does not provide a way to
return other than u characters (unlike ecvt()), which would be
useful in some cases (Inf and NaN, but I dimly remember other
cases).

* When implementing F.RDP, it would have been useful to have fcvt()
(where you specify the number digits after the decimal point) in
addition to ecvt()/REPRESENT (where you specify the total number of
digits).

Another issue is that ecvt()/ecvt_r() has been removed from POSIX,
which instead recommends using sprintf(); I don't see an easy way to
implement REPRESENT based on sprintf().

krishna...@ccreweb.org

unread,
Jul 25, 2017, 7:13:20 AM7/25/17
to
On Tuesday, July 25, 2017 at 12:35:43 AM UTC-5, minf...@arcor.de wrote:
> Am Dienstag, 25. Juli 2017 04:49:34 UTC+2 schrieb krishna...org:
>
> > Yes, almost, but the problem with specifying nr, np, and nd
> > is that there is no way to align to the decimal point. However,
> > this case is perhaps a special case, and will require special
> > word(s) to handle.
> >
> > Krishna
>
> That's what REPRESENT is for: a building block from which application-specific
> formatted output is easy.

Yes, case 3) can be implemented by using REPRESENT . I haven't tried to implement this case yet.

Krishna

krishna...@ccreweb.org

unread,
Jul 25, 2017, 7:47:08 AM7/25/17
to
On Monday, July 24, 2017 at 9:49:34 PM UTC-5, krishna...org wrote:
> On Monday, July 24, 2017 at 5:24:05 PM UTC-5, Anton Ertl wrote:
> > krishna...org writes:
> ...
...
A good example for the use of case 3) is one in which
the values of a function are tabulated in a column.
Due to the numerical errors changing for different
ranges of the argument, the number of significant
digits will vary along the column. Case 3) is useful
when the output is to be in fixed point.

The following program illustrates this for the case
of one implementation of the error function, although
it uses scientific notation to output the number --
a column of values in scientific notation, aligned
with the decimal point, but having different number
of significant digits within the column, is a separate
case (case 4) from the three cases I considered
previously. The output word, ERF1. , simply uses
SET-PRECISION and FS. to display the result of the
function to the appropriate number of significant
digits.

ftp://ccreweb.org/software/kforth/examples/fsl/demo/sigfig-example.4th

Thus, for case 3), we would have the following output
for the function values of ERF1:

x erf1(x)
--------------------------
0.10 0.1125
0.50 0.5205
1.00 0.8427
2.00 0.99531
3.00 0.999978
4.00 0.9999999842
5.00 0.999999999998

Using case 4), the output would be

x erf1(x)
--------------------------
0.10 1.125e-01
0.50 5.205e-01
1.00 8.427e-01
2.00 9.9531e-01
3.00 9.99978e-01
4.00 9.999999842e-01
5.00 9.99999999998e-01

For this example, using case 3) is preferable to
case 4); however, if the range of the function's
output varies over several orders of magnitude,
then case 4) would be preferable.

Krishna




Ed

unread,
Jul 26, 2017, 4:10:40 AM7/26/17
to
Yes, it's meant to be a primitive from which you can build anything.
Easy, however, it is not. Add to this the spec for REPRESENT is
vague and you have implementations that behave differently (read
broken). End result is nobody uses REPRESENT for anything other
than trivial functions. Exceptions are those who write f/p output
suites (not many of those).

The mess that is REPRESENT also occured in C. The difference is C
never took bullet for the variously implemented ecvt fcvt etc. because
they were never standardized. You can do most things you need by
manipulating C's higher level f/p string functions. The same will occur
should Forth ever standardize functions like (F.) (FS.) (FE.) etc.

If I use REPRESENT at all these days it's likely for tinkering or writing
posts like this :)



minf...@arcor.de

unread,
Jul 26, 2017, 5:20:45 AM7/26/17
to
Yes, unfortunately the standards are too vague in this aspect. So varying
incompatible implementations appeared and we have this mess.

For my part I closely coupled PRECISION with REPRESENT and all fp output
functions are built on the REPRESENT result string (including
+/+INF, +/-ZERO, NAN (not implemented are nan variants)). It's rather
clean and practical.

Troubles can only appear when PRECISION != OUTPUT-FORMAT-WIDTH (minus 1
for the dot). But this just requires some programmer'a discipline to
readjust PRECISION as needed.

I know there are more aspects to be clarified like fp input formats,
handling of leading/trailing zeroes - and the famous dot ambiguity
with double numbers of course (ad nauseam).

And what does the {e-char}=D|d in the >FLOAT specification 12.6.1.0558 mean?
... et cetera


Ed

unread,
Jul 26, 2017, 8:08:03 AM7/26/17
to
Anton Ertl wrote:
> ...
> Another issue is that ecvt()/ecvt_r() has been removed from POSIX,
> which instead recommends using sprintf(); I don't see an easy way to
> implement REPRESENT based on sprintf().
>
> - anton

Well, the steps for doing that have existed since 2011. It just needs
someone with the interest and experience in C to code it.

ftp://ftp.taygeta.com/pub/Forth/Applications/ANS/represent_in_c.zip



krishna...@ccreweb.org

unread,
Jul 26, 2017, 9:02:48 AM7/26/17
to
On Sunday, July 23, 2017 at 10:40:00 PM UTC-5, krishna...org wrote:
...
> I implement a justified, fixed-point output with just
> the nr and nd parameters, which guarantees that I have
> fixed point output with only the specified number of
> digits trailing the decimal point. The field width, nr,
> can then be selected to be nd plus 1 (for the decimal
> point) plus the number of digits in the largest expected
> integer portion of the number, plus 1 for handling the
> sign of the number:
>
> \ Convert r to a formatted fixed point string with
> \ n decimal places
> : f>fpstring ( r n -- a u )
> 1 swap dup >r 0 ?do 10 * loop
> s>f f* fround f>d dup -rot dabs
> <# r> 0 ?do # loop [char] . hold #s rot sign #> ;
>
> \ Print an fp number as a fixed point string with
> \ n decimal places, right-justified in a field of width, w
> : fprint ( r n w -- )
> >r f>fpstring r> over -
> dup 0> IF spaces ELSE drop THEN type ;
> ...

I have renamed F>FPSTRING as F>FPSTR , for consistency with my
notation in kForth's strings.4th, and renamed FPRINT to F.RD ,
to follow Gforth's convention with F.RDP. The n and w parameter
has also been interchanged to follow F.RDP's convention for
F.RD. The new implementation is

\ Convert r to a formatted fixed point string with
\ n decimal places
: f>fpstr ( r n -- a u )
1 swap dup >r 0 ?do 10 * loop
s>f f* fround f>d dup -rot dabs
<# r> 0 ?do # loop [char] . hold #s rot sign #> ;

\ Print an fp number as a fixed point string with
\ n decimal places, right-justified in a field of width, w
: f.rd ( r w n -- )
swap >r f>fpstr r> over -
dup 0> IF spaces ELSE drop THEN type ;


F.RD should have another factor which performs the more
general function of right justifying a string within a
blank string of greater length.

For the time being, these words will be available in
strings.4th, and will provide a way of accomplishing fixed-point,
justified, decimal point-aligned output for tabular output of
floating point numbers, i.e. case 2). Floating point number
output formatting words should probably appear in their own
source library, either fpstrings.x or fpout.x. There is
precedence for the latter.

To handle case 1), the case of right-justified scientific
format with a given number of significant digits, I plan to
implement F.RP . This is not entirely trivial if one wants
to ensure alignment to the decimal point, since the width
of the exponent part of the field may vary with sign of the
exponent and size of the exponent.

These words, F.RD and F.RP, factor the functions of Gforth's
F.RDP into cleaner, easier to use words (in my opinion).
Implementation of formatted output cases 3) and 4) will
require a separate argument which specifies the position
of the decimal point within the field. I don't yet have
names for these words.

Krishna





Anton Ertl

unread,
Jul 26, 2017, 1:39:40 PM7/26/17
to
krishna...@ccreweb.org writes:
>we want to
>display the column of numbers (in units of meters) to
>3 decimal places. However, the integer portion of the
>number may vary from zero to 10 meters. Then, the number
>of significant digits varies from 3 to 5, in this case.
>F.RDP will not guarantee that your output stays in
>fixed point format.

If you guarantee that 0e<=r<=10e, then 6 3 0 F.RDP is guaranteed to
stay in fixed-point format (in the development version). However, the
minimum number of significant digits is 0. If you print 0.000123e,
you need 6 digits after the decimal point to print 3 significant
digits, and your formatting requorements forbid that.

>> but gives exponential notation for
>>
>> 1.23e5 12 6 1 f.rdp \ outputs "1.23000000E5"
>> 1.23e-7 12 6 1 f.rdp \ outputs "1.2300000E-7"
>>
>> What would you prefer instead of exponential notation in these cases?
>>
>This is not ok, because I want fixed point format in
>my column of numbers. The column is not easily readable
>if the format changes, even if the field width is the
>same. My preference is that it stays in fixed point format
>with the specified number of decimal places, e.g.
>
>1.23e5 12 6 1 f.rdp \ outputs "123000.000000"
>1.23e-7 12 6 1 f.rdp \ outputs " 0.000000"
>
>Note that the first number overflows the field width,
>and this is acceptable.

I don't find it acceptable, because it means that not only this field
will become harder to read (misaligned decimal point), but all the
following fields on the line get the same problem as well. If this
happens in several lines, the whole table becomes hard to read. By
contrast, keeping the field width (by switching to exponential
notation) makes the field harder to read, but the rest of the table is
unaffected.

>It means the programmer did
>not estimate his required field width correctly, and
>he can go back and fix his field width if he wants
>fixed point output.

You could say the same if F.RDP switches to exponential notation.

But making the field wider may not be an option (because that would
cause the line width to be exceeded). Then it is preferable to show
the number in exponential notation rather than a too-wide fixed-point
notation.

Concerning your

>1.23e-7 12 6 1 f.rdp \ outputs " 0.000000"

That would be wrong, because it shows 0 significant digits. If you
want that, you can do

1.23e-7 12 6 0 f.rdp \ outputs " 0.000000" in the development version

I fixed a bug in Gforth where F.RDP would switch to exponential
notation for numbers close to 0 even if you ask for 0 significant
digits.

> If, however,
>it is important to express the column of numbers to
>a fixed number of significant digits, then the programmer
>should have chosen scientific notation as the output
>format.

Printing the whole column in hard-to-read exponential format just
because one or a few entries would not fit in fixed point format would
be perverse.

>I feel that F.RDP tries to do too many things. It suffers
>from the same problem as F~ in ANS-Forth.

No. For every use of F~, you would be better of using F~ABS, F~REL,
or F=. You cannot replace uses of F.RDP with F.FIXED and
F.EXPONENTIAL. The format depends on the number to print itself if
you want to keep the field fixed-width (yes, I know you don't want
that).
14 5 5 f.rdp shows these numbers as:

3.14159
6.62607000E-34
-14.14210 ok

It's easier to see here how big the first and the third numbers are.

>If you set np>nr, both the first and second arguments to
>F.RDP are meaningless -- the output is determined only
>by the number of significant digits, and the sign of the
>number. This does not make for a nicely aligned
>justified column, unless you assume the sign to be
>uniform.

The only meaning of nr and np are then to cause exponential notation,
yes. I count these as the last and next-to-last arguments, though.
Given that exponential notation is hard to read anyway, aligning parts
of exponential notation seems a waste of space to me. But yes, if you
want an aligned exponential notation output, F.RDP is not for you.

>> >case 2)
>> >The column output should display a fixed point format
>> >with a constant number of decimal places (in contrast
>> >with a constant number of significant digits, as in
>> >case 1). The number of of significant digits may vary
>> >for each number, e.g.
>> >
>> >12345678901234
>> >--------------
>> > 21.3657
>> > -1.0021
>> > 1020.7448
>> > -15384.0931
>> >
>> >Once again, we use a field width of 14. Now, the number
>> >of decimal places is constant, but the number of
>> >significant digits vary from row to row. The numbers are
>> >all aligned to the decimal point, which is very easy to
>> >do since right justification of the output string within
>> >the field will produce the appropriate alignment.
>>
>> That's pretty much what the F.RD above gives you, if you limit
>> yourself to numbers that fit fixed-point notation. However, what do
>> you do if you have to print 1.23456e20 or 1.23456e-10?
>>
>
>I assume you meant F.RDP in the sentence above.

I meant : F.RD 1 F.RDP ;

>If you have to print numbers over such a wide range of
>magnitude as 1e20 and 1e-10, you should choose case 1),
>i.e. use scientific notation for the entire column, not
>fixed point output. This is a programmer decision, not one
>which should be made by the output word.

I as a programmer don't want the whole column in exponential notation
just because it contains one or two outliers. That's why F.RDP
behaves the way it does.

>> >case 3)
>> >The column output is desired in fixed point format within
>> >a constant field width, but with neither a constant number
>> >of decimal places nor a constant number of significant
>> >digits. Alignment should be to the decimal point.
>> >
>> >12345678901234
>> >--------------
>> > 21.3657206
>> > 1.0021
>> > -516.7
>> > 65532.
>> >
>> >The range of numbers in this last example is exaggerated
>> >from the typical use cases I've encountered, but it is
>> >common to need this type of formatting within a fixed-width
>> >column.
>>
>> Common? Not really. I cannot remember ever seeing this before.
>>
>
>It is required when a column of numbers aren't like-kinds
>of quantities, for example, and need different tolerances
>(different number of decimal places) and different number
>of significant digits (scale of numbers). Even for like-kind
>of quantities it is sometimes needed.

Apparently you can't point me to such a table, either. I am sure
there is some out in the wide world, but it's definitely not common.

krishna...@ccreweb.org

unread,
Jul 26, 2017, 7:14:17 PM7/26/17
to
On Wednesday, July 26, 2017 at 12:39:40 PM UTC-5, Anton Ertl wrote:
> krishna...org writes:
...
> >It is required when a column of numbers aren't like-kinds
> >of quantities, for example, and need different tolerances
> >(different number of decimal places) and different number
> >of significant digits (scale of numbers). Even for like-kind
> >of quantities it is sometimes needed.
>
> Apparently you can't point me to such a table, either. I am sure
> there is some out in the wide world, but it's definitely not common.
>

See the error function table examples I posted in this thread.

Krishna

Anton Ertl

unread,
Jul 27, 2017, 8:09:31 AM7/27/17
to
Any references to something not by you?

<https://en.wikipedia.org/wiki/Error_function> does not contain a
table, but <https://de.wikipedia.org/wiki/Fehlerfunktion#Wertetabelle>
does, and the erf(x) and erfc(x) entries in this table can be printed
with 9 7 0 F.RDP.

But let's look at the table you produced:

x erf1(x)
--------------------------
0.10 0.1125
0.50 0.5205
1.00 0.8427
2.00 0.99531
3.00 0.999978
4.00 0.9999999842
5.00 0.999999999998

This requires precision information that is not present in the FP
number itself, so you have to supply it as an additional parameter.
If this parameter is the number of digits after the decimal point to
be printed, you can have:

: .erf1 ( r n -- )
dup 2 + swap 0 f.rdp ;

or, if you want trailing spaces in order to print another field:

: .erf ( r n -- )
>r r@ 2 + r@ 0 f.rdp 12 r> - spaces ;

krishna...@ccreweb.org

unread,
Jul 27, 2017, 7:34:25 PM7/27/17
to
On Thursday, July 27, 2017 at 7:09:31 AM UTC-5, Anton Ertl wrote:
> krishna...org writes:
> >On Wednesday, July 26, 2017 at 12:39:40 PM UTC-5, Anton Ertl wrote:
> >> Apparently you can't point me to such a table, either. I am sure
> >> there is some out in the wide world, but it's definitely not common.
> >>
> >
> >See the error function table examples I posted in this thread.
>
> Any references to something not by you?
>

Despite your doubt that case 3) is actually used in practice, I hope you can see the logic of its utility as a useful tabular output format. But, to answer your question more directly, have a look at ref. 1 in h2XJ0.fs:

\ References:
\
\ 1. K. Pachucki, "Born-Oppenheimer potential for H_2,"
\ Phys. Rev. A 82, 032509 (2010).
\

If you don't have access to the published article, a version of it may be found on arXiV.org:

https://arxiv.org/abs/1007.0322

In particular, take a look at Tables II, IV, and V.

Yes, case 3) is commonly used to indicate the changing precision of values within a column. Note the alignment to the decimal point.

> <https://en.wikipedia.org/wiki/Error_function> does not contain a
> table, but <https://de.wikipedia.org/wiki/Fehlerfunktion#Wertetabelle>
> does, and the erf(x) and erfc(x) entries in this table can be printed
> with 9 7 0 F.RDP.
>

The algorithm used to generate the table on that page well may have 7 decimal places of accuracy. We have a Forth version as well, as part of the FSL, which also provides higher accuracy than erf1.

> But let's look at the table you produced:
>
> x erf1(x)
> --------------------------
> 0.10 0.1125
> 0.50 0.5205
> 1.00 0.8427
> 2.00 0.99531
> 3.00 0.999978
> 4.00 0.9999999842
> 5.00 0.999999999998
>
> This requires precision information that is not present in the FP
> number itself, so you have to supply it as an additional parameter.

Sure, that's the point in specifying the number of decimal places for fixed point output. The word would be something like F.RDx where x specifies the position of the decimal point in the field.

> If this parameter is the number of digits after the decimal point to
> be printed, you can have:
>
> : .erf1 ( r n -- )
> dup 2 + swap 0 f.rdp ;
>
> or, if you want trailing spaces in order to print another field:
>
> : .erf ( r n -- )
> >r r@ 2 + r@ 0 f.rdp 12 r> - spaces ;
>

Will these words align to the decimal point when the integer portion has a non-uniform number of digits?

Krishna

Anton Ertl

unread,
Jul 28, 2017, 8:45:36 AM7/28/17
to
krishna...@ccreweb.org writes:
>On Thursday, July 27, 2017 at 7:09:31 AM UTC-5, Anton Ertl wrote:
[...]
>\ References:
>\
>\ 1. K. Pachucki, "Born-Oppenheimer potential for H_2,"
>\ Phys. Rev. A 82, 032509 (2010).
>\
>
>If you don't have access to the published article, a version of it may be found on arXiV.org:
>
>https://arxiv.org/abs/1007.0322
>
>In particular, take a look at Tables II, IV, and V.

Thanks, that was what I was looking for.

>> If this parameter is the number of digits after the decimal point to
>> be printed, you can have:
>>
>> : .erf1 ( r n -- )
>> dup 2 + swap 0 f.rdp ;
>>
>> or, if you want trailing spaces in order to print another field:
>>
>> : .erf ( r n -- )
>> >r r@ 2 + r@ 0 f.rdp 12 r> - spaces ;
>>
>
>Will these words align to the decimal point when the integer portion has a non-uniform number of digits?

These words are designed for the error function, with one digit (or
"-") before the decimal point. A more general variant would be:

: f.rdi { F: r nr nd ni -- }
\ print r in field of width nr, with the decimal point coming after ni
\ digits and nd digits behind the decimal point, and the rest of the
\ field filled with blanks. If r does not satisfy this format,
\ exponential notation is used.
r nd ni + 1+ dup nd 0 f.rdp nr swap - spaces ;

12.3456e 15 3 3 '|' emit f.rdi '|' emit \ prints | 12.346 |

krishna...@ccreweb.org

unread,
Jul 28, 2017, 6:56:25 PM7/28/17
to
On Friday, July 28, 2017 at 7:45:36 AM UTC-5, Anton Ertl wrote:
...
> ... A more general variant would be:
>
> : f.rdi { F: r nr nd ni -- }
> \ print r in field of width nr, with the decimal point coming after ni
> \ digits and nd digits behind the decimal point, and the rest of the
> \ field filled with blanks. If r does not satisfy this format,
> \ exponential notation is used.
> r nd ni + 1+ dup nd 0 f.rdp nr swap - spaces ;
>
> 12.3456e 15 3 3 '|' emit f.rdi '|' emit \ prints | 12.346

In the x.R words, the "R" indicates right justification of the numeric output within the field, which isn't really an accurate way to describe the formatting for cases 3) and 4). Since we
want alignment to the decimal point in those cases, it might be more appropriate to use x.A in those cases, e.g. F.RDI becomes F.ADI for case 3) and we would have F.API for case 4). Both of
these words require three integer arguments. I considered the last argument, ni, as being the offset position of the decimal point from the start of the field, which might be different from the way you are using it (or maybe they are equivalent -- I'm not sure).

Thus far, the word names I would suggest for the 4 proposed cases are:

case 1)

F.RP ( nw np -- ) ( F: r -- ) or ( r nw np -- )

case 2)

F.RD ( nw nd -- ) ( F: r -- ) or ( r nw nd -- )

case 3)

F.ADI ( nw nd ni -- ) ( F: r -- ) or ( r nw nd ni -- )

case 4)

F.API ( nw np ni -- ) ( F: r -- ) or ( r nw np ni -- )


A separate output case, case 5), can be provided for F.RDP, which doesn't guarantee fixed or scientific format but selects the one most appropriate to fit into a field of width, nw. I can see the utility of having such an output case as well.

It will be useful to find the common factors needed for implementation of such a set of words, e.g. the word DP-ALIGN, as suggested to me by Ed. A variant of F.RDP which produces the output as a string could potentially be a common factor.

Krishna


0 new messages