Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GForth: Convert floating point number to String

Tags:

forth

gforth

A simple question that turned out to be quite complex:

How do I turn a float to a String in GForth? The desired behavior would look something like this:

1.2345e fToString \ takes 1.2345e from the float stack and pushes (addr n) onto the data stack
like image 733
nitowa Avatar asked Dec 05 '18 23:12

nitowa


2 Answers

After a lot of digging, one of my colleagues found it:

f>str-rdp ( rf +nr +nd +np -- c-addr nr )

https://www.complang.tuwien.ac.at/forth/gforth/Docs-html-history/0.6.2/Formatted-numeric-output.html

Convert rf into a string at c-addr nr. The conversion rules and the meanings of nr +nd np are the same as for f.rdp.

And from f.rdp:

f.rdp ( rf +nr +nd +np – )

https://www.complang.tuwien.ac.at/forth/gforth/Docs-html/Simple-numeric-output.html

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.

In humanly readable terms, these functions require a number on the float-stack and three numbers on the data stack.

The first number-parameter tells it how long the string should be, the second one how many decimals you would like and the third tells it the minimum number of decimals (which roughly translates to precision). A lot of implicit math is performed to determine the final String format that is produced, so some tinkering is almost required to make it behave the way you want.

Testing it out (we don't want to rebuild f., but to produce a format that will be accepted as floating-point number by forth to EVALUATE it again, so the 1.2345E0 notation is on purpose):

PI 18 17 17 f>str-rdp type \ 3.14159265358979E0 ok
PI 18 17 17 f.rdp          \ 3.14159265358979E0 ok
PI f.                      \ 3.14159265358979  ok
like image 126
nitowa Avatar answered Dec 09 '22 02:12

nitowa


I couldn't find the exact word for this, so I looked into Gforth sources.

Apparently, you could go with represent word that prints the most significant numbers into supplied buffer, but that's not exactly the final output. represent returns validity and sign flags, as well as the position of decimal point. That word then is used in all variants of floating point printing words (f., fp. fe.).

Probably the easiest way would be to substitute emit with your word (emit is a deferred word), saving data where you need it, use one of available floating pint printing words, and then restoring emit back to original value.

I'd like to hear the preferred solution too...

like image 43
Vlad Avatar answered Dec 09 '22 04:12

Vlad