### 1. Phix, numbers, printf, log10

Phix 64-bit, but it similarily happens with 32-bit:

printf(1, "%1.2e", 2.25)
2.26e+0

printf(1, "%1.2e", 2.48)
2.49e+0

printf(1, "%1.2e", 2.428)
2.42e+0

It happens with all kinds of numbers, and any number of decimal digits â€” the last digit tends to be hit or miss.

Also, though a bit less annoying, %f has a "5" rounding issue, this too happens with all kinds of numbers and any number of decimal digits (also happens with Euphoria, as far as I can remember):

printf(1, "%0.1f", 2.75)
2.8
rounding up

printf(1, "%0.1f", 2.85)
2.8
rounding down

Something else: what is the best way to find the magnitude (exponent in scientific notation) of x? I've been using floor(log10(x)), but, probably due to how log10 is calculated, it's not entirely reliable:

? floor(log10(1000))
3
correct

? floor(log10(1000 - 1e-16))
2
correct

? floor(log10(1000 + 1e-16))
2

printf("%e", x) seems to get the exponent more reliably, but using sprintf("%e", x) and then reading the number after the "e" from the string is rather clumsy, and rounding can become an issue, too.

I think I've managed to work around these issues (thought this before, though), but things might be easier if sprint were able to return more than 10 significant digits (I'd be content with 15).

Thanks for any help or clarification where I may be confused,
Robert

### 2. Re: Phix, numbers, printf, log10

I briefly glanced at this last night, decided I needed to sleep on it, it didn't help.
Historically these sort of printf() issues have required fairly lengthy debug sessions...
The 0.5 rounding does seem to disagree with the docs and explicit use of round()/bankers_rounding(),
I think I should probably start with that before the first three. (see #3)

But I think the logarithm thing is the first thing to get out the way.
A debug session to remind myself precisely what %e does is probably in order...
Though I'm not getting the same results: I get 3 for all three, on 64 and 32 bit.
I get the expected results (323) for +/-1e12 on 64 bit and +/-1e11 on both 32 and 64bit...
In particular, I am not getting "2 badly wrong" under any circumstances.... So:

```? {11,log10(1000 - 1e-11)-3,log10(1000 + 1e-11)-3}
? {12,log10(1000 - 1e-12)-3,log10(1000 + 1e-12)-3}
? {13,log10(1000 - 1e-13)-3,log10(1000 + 1e-13)-3}
? {14,log10(1000 - 1e-14)-3,log10(1000 + 1e-14)-3}
? {15,log10(1000 - 1e-15)-3,log10(1000 + 1e-15)-3}
? {16,log10(1000 - 1e-16)-3,log10(1000 + 1e-16)-3}
--64-bit:
--{11,-4.035400486e-15,4.650576799e-15}
--{12,-1.268516541e-16,7.418111264e-16}
--{13,2.641116492e-16,3.510646634e-16}
--{14,3.031429274e-16,3.118165449e-16}
--{15,3.070460552e-16,3.07913417e-16}
--{16,3.072628957e-16,3.074797361e-16}
--32-bit:
--{11,-3.996802889e-15,4.884981309e-15}
--{12,0,4.440892099e-16}
--{13,0,0}
--{14,0,0}
--{15,0,0}
--{16,0,0}
-- ie only getting a different SIGN at the +/- 1e11/12 mark.
```

One thing I will say is that logarithms are inherently an approximation, and I have found a few
posts that confirm my initial suspicion that a test against power(10,res) is needed to be sure.

PS Can you explain what you are using the magnitude for? Exact may not match what %e delivers.
(for instance that willmay start printing "9.99999999" then round up to 1.0 and bump the exponent)
Do you need the magnitude of negative numbers? Is 0.01 ==> -2 ok/wanted?
What are the largest(/smallest) numbers you need a magnitude for?

### 3. Re: Phix, numbers, printf, log10

RobertS said...

%f has a "5" rounding issue, this too happens with all kinds of numbers and any number of decimal digits (also happens with Euphoria, as far as I can remember):

printf(1, "%0.1f", 2.75)
2.8
rounding up

printf(1, "%0.1f", 2.85)
2.8
rounding down

Ah, the problem here is that 2.85 cannot be held exactly, and the nearest IEEE-754 representation is ~2.849999999999999999 which is correctly rounded down.
You might be able to do something with rationals, otherwise that's a fundamental and unsolveable hardware issue. [At least now I can start on the first three.]

PS I stumbled on what might be a fairly nifty magnitude() function, but it needs the range of values it must cope with, from you, and probably a bit of polishing, before I can post it.

Update: I've now got a fix for the first part ("%e" was not updating f the same way "%f" does as it printed digits):

builtins\VM\pprntfN.e line ~222 said...
```            digit = floor(f)
--21/2/24:
f = (f-digit)*10
```

and

builtins\VM\pprntfN.e line ~248 said...
```--21/2/24
--                  f = (f-digit)*10
digit = floor(f)
f = (f-digit)*10
```

Many thanks. I'd recommend running "p -test" after editing that in and running "p -cp", to make sure nothing got broken.

### 4. Re: Phix, numbers, printf, log10

petelomax said...

Though I'm not getting the same results: I get 3 for all three, on 64 and 32 bit.

This is weird. I swear,

? floor(log10(1000))
? floor(log10(1000 - 1e-16))
? floor(log10(1000 + 1e-16))

gives me
3
2
2

(Win 10, Phix 1.0.4 64-bit.) I suppose log10(1000) is calculated more precisely than log10(not exactly 1000).

Also found this:

99800000000000000 is integer
9.98 * power(10, 16) is integer
9.98e16 is not integer

But I must admit that I'm picking really very tiny nits here.

What got me started now was the
printf(1, "%1.2e", 2.48)
2.49e+0

thing, when I began experimenting with 64-bit Phix for the next Hypatia version.

petelomax said...

Can you explain what you are using the magnitude for?

For two related purposes: to round numbers to n significant digits, and to print numbers with n significant digits.

To round a number to n digits I have to get the magnitude, divide the number by power(10, magnitude) so that there is one digit before the decimal point, then I can use round() to round it to n-1 digits after the decimal point, then multiply the rounded result with the original magnitude. If there is a simpler or better way of doing it, I'm not aware of it.

(If round() gets the last digit wrong by +/-1, so be it, but what I want to avoid is the risk of rounding the number to a wrong number of digits, which might give a much larger error.)

For printing numbers with n significant digits (up to 15 with 64-bit, which sprint() doesn't do) I use a similar method â€” divide the number by power(10, magnitude+1), convert it to a string with sprintf() so that the string starts with "0.", remove the "0.", then insert the decimal point where it belongs (or add leading zeros) according to the original magnitude.

Previously I used sprintf() with "%e", and read the magnitude from what's after "e" in the string, which meant that whichever way sprintf() rounded the number, mantissa and exponent were consistent. Since finding that "%e" often gets the last digit wrong (see above, 2.48), I use "%F" which doesn't, but this requires me to get the exponent from somewhere else, and this opens up the possibility of getting it wrong (999... getting rounded up to 1000... by sprintf(), but log10 says magnitude is still that of 999..., and the result is printed as 100...). I think I got it under control now, but I'm still wary.

I know that some inaccuracies are unavoidable, due to binary vs. decimal â€” I only want to understand where they lurk, which ones I could avoid, which ones I can work around, which ones need special attention because they may possibly make something wrong by a factor of 10. And, what to tell the hypothetical user of the upcoming 64-bit version of Hypatia about how far they can, or can not, trust the results. I suppose it will have to be, "Internal accuracy is 18-19 digits, I show you only 15, but the last one may still be wrong by +/-1" â€” I just want to be sure it's never more than that.

So, this is a fact finding mission, not a complaint!
Thanks again,
Robert

### 5. Re: Phix, numbers, printf, log10

petelomax said...

Update: I've now got a fix for the first part ("%e" was not updating f the same way "%f" does as it printed digits):

Sorry, maybe it's my fault and I did it wrong, but now I get:

printf(1, "%e", 12)
1.220000e+1

It works for numbers < 10, gets the last digit right, but when there is more than 1 digit before the decimal point, the digit before the decimal point gets repeated:

printf(1, "%e", 123.456)
1.2334563e+2

But I may have misunderstood how to edit the file. I now have

```        else
digit = floor(f)
--21/2/24:
f = (f-digit)*10
end if
result &= digit+'0'
if precision>0 then
```

and

```--30/10/21
else
--21/2/24
digit = floor(f)
f = (f-digit)*10
end if
--12/7/16:
if digit=10 then exit end if
```

Anyway, when this is fixed, it will help a lot, thank you!

Robert

### 6. Re: Phix, numbers, printf, log10

P.S.

petelomax said...

Exact may not match what %e delivers.
(for instance that willmay start printing "9.99999999" then round up to 1.0 and bump the exponent)

That's fine with me. When it rounds up the number and bumps the exponent, then this is what it is â€” I don't expect accuracy beyond 18 digits. I'm only worried that (the way I'm doing it, using log10) one might possibly happen without the other.

petelomax said...

Do you need the magnitude of negative numbers? Is 0.01 ==> -2 ok/wanted?
What are the largest(/smallest) numbers you need a magnitude for?

a) no
b) yes
c) no limit

but, with %e working reliably, I think I'd have all I need.

Thanks again!
Robert

### 7. Re: Phix, numbers, printf, log10

RobertS said...

This is weird.

Agh, yep, my bad: it goes wrong on a properly built 64-bit - I was using a built-by-32-bit thing,
which happened to go wrong in completely different way, that just happened to undermine that test...
(I've also just realised that means I have always shipped a duff 64-bit-for-Linux executable...)
Anyway, it simply turns out to be exceeding the accuracy limits of log10:

```?log10(1000 - 1e-16)-3 -- -2.168404345e-19 (right sign-wise)
?log10(1000 + 1e-16)-3 -- -2.168404345e-19 (wrong sign-wise)
?log10(1000 - 1e-15)-3 -- -4.33680869e-19 (right sign-wise)
?log10(1000 + 1e-15)-3 -- 2.168404345e-19 (right sign-wise)
?atom_to_float80(log10(1000 - 1e-16))&-1 -- {255,255,255,255,255,255,255,191,0,64'@',-1}
?atom_to_float80(log10(1000 + 1e-16))&-1 -- {255,255,255,255,255,255,255,191,0,64'@',-1}
?atom_to_float80(log10(1000 - 1e-15))&-1 -- {254,255,255,255,255,255,255,191,0,64'@',-1}
?atom_to_float80(log10(1000 + 1e-15))&-1 -- {1,0,0,0,0,0,0,192,0,64'@',-1}
```

So log10 of 1000 +/- 1e-16 returns the exact same value, not much printf() etc can do about that.

RobertS said...

Also found this:

99800000000000000 is integer
9.98 * power(10, 16) is integer -- <<== erm?
9.98e16 is not integer

You quite sure about that? ?apply({99800000000000000,9.98 * power(10, 16),9.98e16},integer) gets me {1,0,0}.
Take a look at ptok.e/completeFloat(), line 1603. There's a glaring error, try ?{1e1000,1e2000}, which I just fixed by:

```--22/2/24:
--      if exponent>308 then
if exponent>308 and machine_bits()=32 then
-- rare case: avoid power() overflow
```

There may be a case for "exponent>4932" under 64 bit, and/or similar on the -ve bounds, and rather than capping it
at 1000, use an is_inf() [which almost certainly did not exist when I wrote that code] check inside the loop.

As you can see, otherwise I modified that 2, 9, and 14 years ago, ie not very often, and the last time looks suspiciously similar to the case you just uncovered. The matching entry in the readme was:

```28/09/2022: Bugfix: 1e18 was not generating an integer on 64bit. Rather than
(further) mess with %opPow in VM\pPower.e, I simply added a *10
loop in ptok.e/completeFloat() for (decimal) exponents 0..20.
Aka: integer i=1e18 <== "type error (storing float in integer)".
```

In fact I suspect that test should [now] be elsif exponent=18 [and machine_bits()=64] then, or probably
better, line 321 in VM\pPower.e should be cmp rcx,18 and that branch/loop in completeFloat() removed.
(I've already made the latter two of those changes, and tested them, on the development version.)

It should be possible to defer the TokN += fraction/dec statement until after we also have exponent,
resurrect the "end if / exponent -= ndp / if exponent then" and do something a little better/smarter.
At that mid-point, everything that can be an integer should still be one. Using the 32-bit 1e308 limit for clarity,
though the same applies to the 64-bit 1e4932 limit, one thing we must not do is temporarily create 4.99e309 on our
way to creating 4.99e307, iyswim, but otherwise we can re-assemble our 4, 99, and 307 any way we like, such as
(4*100+99)*power(10,305) aka (TokN*power(10,ndp)+fraction)*[/]power([-](exponent-ndp)), to keep things integer.
Please keep a list of anything that goes wrong, however briefly, so I can later add them all to "p -test".
[No longer entirely sure, but I think the /= power(10,-exponent) was put there for accuracy reasons, which may
only matter for numbers very close to said limits, or very nearly zero.]

Anyhow, feel free to have a play with completeFloat(), performance is not even slightly an issue, my only concern
would be that 32-bit does not get crippled, and your only concern should be having a backup of ptok.e and p[w].exe
in case things go south, you also have "p -test" to keep you out of trouble. FYI, I run my editor etc off a manual
copy of pw.exe, so I don't have to keep on shutting things down to rebuild it. It is of course entirely your choice
to play with that in the compiler itself, or take a copy to play with outside, or even incorporate into Hypatia, but
rest assured the first of those sounds far scarier than it actually is.

I am now thinking that %e is in fact the best way to get the magnitude:

```function magnitude(atom x)  --, dflt=x|0)
--  if is_inf(x) or is_nan(x) then return x|0|dlft end if   -- ??
string s = sprintf("%.20e",x)
integer e = find('e',s),
n = to_number(s[e+1..\$])
--  atom chk = power(10,n)              -- ??
--  if x>=chk*10 then n += 1            -- ??
--  elsif x<chk then n -= 1 end if      -- ??
return n
end function
```

You are of course quite right about several edge cases being cause for concern, though, and certainly enough to prevent me from even thinking of adding something like that as a new builtin, at least just yet.

RobertS said...

But I must admit that I'm picking really very tiny nits here.
So, this is a fact finding mission, not a complaint!

Don't worry, this stuff is all very welcome!
Should you feel there is something missing from the docs, try writing something I can paste right in,
and tell me precisely where you think that would best go.

RobertS said...

printf(1, "%e", 12)
1.220000e+1

Oops, I'm on it...

PS for anyone concerned about that "duff 64-bit-for-Linux executable":

```printf(1,"%.20f\n",PI)
-- 3.14159265358979323851 -- after "/.p -c p" (0.0005e-16 out)
```

I have improved the build script so that will no longer occur in 1.0.5 and later

### 8. Re: Phix, numbers, printf, log10

petelomax said...
RobertS said...

Also found this:

99800000000000000 is integer
9.98 * power(10, 16) is integer -- <<== erm?
9.98e16 is not integer

You quite sure about that? ?apply({99800000000000000,9.98 * power(10, 16),9.98e16},integer) gets me {1,0,0}.

Ooops, my mistake, sorry! By mistake I tested two different values:

? integer(9.98e16)
0
? integer(9.989 * power(10, 16))
1

but, 9.989e16 is integer, too, and 9.98 * power(10, 16) is not - so, exx and power(10, xx) are consistent. There remains the (to me) mystery that 9.98e16 is not an integer, while 9.989e16 is, but I have yet to look closer at all the information you've given.

But, back to 2.85 ...

petelomax said...

Ah, the problem here is that 2.85 cannot be held exactly, and the nearest IEEE-754 representation is ~2.849999999999999999 which is correctly rounded down. You might be able to do something with rationals, otherwise that's a fundamental and unsolveable hardware issue.

This explains why printf(1, "%0.1f\n", 2.85) says 2.8.

But, round() correctly rounds 2.85 up â€” printf(1, "%0.1f\n", round(2.85, 10)) says 2.9.

From what I've seen so far, round() (however it does it) may indeed solve this unsolveable issue, or haven't I tested enough and am too optimistic?

Thanks again!
Robert

### 9. Re: Phix, numbers, printf, log10

RobertS said...

printf(1, "%e", 12)
1.220000e+1

OK, I've aligned the "fwk" side with the "(f-digit)*10" side and got rid of fadj, and pushed all this to https://raw.githubusercontent.com/petelomax/Phix/master/builtins/VM/pprntfN.e which you may find much easier:

```@ -218,20 +218,26 @@ end for
fwk += epwr
digit += 1
end while
--24/2/24:
f -= fwk
else
digit = floor(f)
--21/2/24:
f = (f-digit)*10
end if
result &= digit+'0'
if precision>0 then
result &= '.'
dotdone = 1
--24/2/24:
--1/11/15
--          for i=1 to precision do
for i=1 to precision-(charflag='g') do
if ewk>0 then
--24/2/24:
--                  f -= fwk
ewk -= 1
epwr = power(10,ewk)
fwk = 0--epwr
@ -240,19 +246,25 @@ end for
fwk += epwr
digit += 1
end while
--24/2/24:
--30/10/21
f -= fwk
else
--21/2/24
--                  f = (f-digit)*10
digit = floor(f)
f = (f-digit)*10
--24/2/24:
end if
--12/7/16:
if digit=10 then exit end if
result &= digit+'0'
end for
--24/2/24:
else
if ewk>0 then
f -= fwk
```

Clearly "p -test" is missing a whole bunch of "%e"-related stuff.

### 10. Re: Phix, numbers, printf, log10

RobertS said...

but, 9.989e16 is integer, too, but 9.98e16 is not an integer

I expect that's just the luck of the draw, 9.98 is out by the tiniest amount, as is 9.989, but after multiplication by 1e16 one of said tiniest amounts ends up being zero (see below)...

RobertS said...

But, round() correctly rounds 2.85 up â€” printf(1, "%0.1f\n", round(2.85, 10)) says 2.9.

From what I've seen so far, round() (however it does it) may indeed solve this unsolveable issue, or haven't I tested enough and am too optimistic?

Your guess is as good as mine.. (2.75 can be represented exactly, as can 28.5, which is why I used them here):

```?(2.85-2.75)*10-1   -- 8.881784197e-16 (on 32-bit, -8.67361738e-19 on 64-bit)
?(2.85*10)-28.5     -- 0 (on both)
```

Probably pretty much impossible to say precisely why, without studying the FPU core transistor-by-transistor...
Presumably some very clever minds found some weird ways to make the FPU more accurate than simple logic might suggest.
You probably are being a smidge optimistic if you think that sort of thing is always going to work out in your favour (but o/c use it if >=51%).
Disclaimer: round() is based on Euphoria code, RobC quite likely tried out several approaches and picked the best he could find.
Note that for obvious reasons printf() works digit-by-digit then rounds, so always matching round() is simply not an option.

### 11. Re: Phix, numbers, printf, log10

Thank you for the %e fix, I'll try it out tomorrow.

petelomax said...

Note that for obvious reasons printf() works digit-by-digit then rounds, so always matching round() is simply not an option.

I am doing this, rounding the value to the specified number of decimal digits before calling sprintf():

```-- atom r is the number to be printed
-- integer fmt is the number of decimal digits
-- string rf is a temporary variable
-- string rr is the formatted result (yes, bad habit of mine, to use minimalistic variable names)

r = round(r, power(10, fmt))
rf = "%1." & sprint(fmt) & "f"
rr = trim(sprintf(rf, r))
```

I'm not sure if it's 100%, but I think it is a significant improvement.

I've also written a little function to work around the fact that power() uses logarithms, and therefore doesn't always give integer results for power(a, b) even if a and b are integer â€” seems to work fine (updated March 9):

```function power_int(atom a, atom b, integer maxb = 59)

atom p
p = power(a, b)
if integer(a) and integer(b) and b > 0 then           -- if result should be integer ...
if not integer(p) then                        -- ... but isn't
if abs(p) < 1e18 and b <= maxb then   -- maxb limit to avoid using too much time for this, not sure if it is necessary
p = a                            -- power(2, 60) is > 1e18, therefore 59 is the highest possible exponent
for j = 2 to b do
p = p * a
end for
end if
end if
end if
return p
end function
```

? power(3, 18)
? integer(power(3, 18))
? power_int(3, 18)
? integer(power_int(3, 18))
387420489.0
0
387420489
1

What I still find a bit troubling, though, is that 8.98 * 100 is not an integer. In the upcoming 64-bit version of Hypatia I'll use a function (which can be disabled) which rounds non-integer values to 17 significant digits, and if that is integer, then it replaces the original value â€” meaning, everything very close to integer is considered to be intended to be integer â€” this also resolves the 8.98* 100 issue well enough for me.

I think that, with %e working correctly, I have all I need for all practical purposes. Still have to be wary, though.

Robert

### 12. Re: Phix, numbers, printf, log10

petelomax said...
RobertS said...

printf(1, "%e", 12)
1.220000e+1

OK, I've aligned the "fwk" side with the "(f-digit)*10" side and got rid of fadj, and pushed all this to https://raw.githubusercontent.com/petelomax/Phix/master/builtins/VM/pprntfN.e which you may find much easier:

I copied that pprntfN.e file and rebuilt p.exe, but I'm afraid there is still something wrong:

printf(1, "%e", 38.24)
3.802400e+1

But this seems to be the last remaining issue for me.

I've written a replacement for to_number() that reliably reads 8.98e2 as integer (it removes the decimal point from the mantissa which thus becomes integer, and then adjust the exponent according to where the decimal point had been).

Also, I think I've resolved the "magnitude" issue (which I need for rounding numbers to n significant digits) â€” m is floor(log10(a)), which may possibly be wrong for values very close to powers of 10, but then I check if the following condition is met: power(10, m) <= a < power(10, m+1) â€” if not, m gets corrected. Not very elegant, but I think it works.

Should anyone be interested I'll gladly go into details.

So, apart from %e, and as long as nothing unexpected comes up, I think I have what I need!

Robert

### 13. Re: Phix, numbers, printf, log10

RobertS said...
petelomax said...

OK, I've aligned the "fwk" side with the "(f-digit)*10" side and got rid of fadj, and pushed all this to https://raw.githubusercontent.com/petelomax/Phix/master/builtins/VM/pprntfN.e which you may find much easier:

printf(1, "%e", 38.24)
3.802400e+1

I missed a *10, new version at same link

### 14. Re: Phix, numbers, printf, log10

petelomax said...
RobertS said...
petelomax said...

OK, I've aligned the "fwk" side with the "(f-digit)*10" side and got rid of fadj, and pushed all this to https://raw.githubusercontent.com/petelomax/Phix/master/builtins/VM/pprntfN.e which you may find much easier:

printf(1, "%e", 38.24)
3.802400e+1

I missed a *10, new version at same link

Yes, this works, thank you!

But, after I rebuilt Phix, p -test now says:

Testing[64]: C:\Phix\test\t64struct.exw
constructor five(5) called
destructor ~five(5) called
diag looping, error code is 1, era is #00817857
exception code #C0000005 at #0000000000830734
etc.

I have no idea what this means, and I haven't noticed anything not working, but I thought I should let you know.

Thank you again for all your great work!
Robert

### 15. Re: Phix, numbers, printf, log10

RobertS said...

But, after I rebuilt Phix, p -test now says:
I have no idea what this means, and I haven't noticed anything not working, but I thought I should let you know.

Thanks for letting me know. Entirely independently of all this I had also previously (8/2/24)

```Bugfix: couple of sprint() in pDiagN.e still passing maxlen to asChar.
```

So that does not happen here on the dev system, and I assume it is/was something mid-exception handling.
Should you need it, grab yourself an updated copy of pDiagN.e, and that should fix it. Or just leave it till 1.0.5 ships.

### 16. Re: Phix, numbers, printf, log10

petelomax said...

Should you need it, grab yourself an updated copy of pDiagN.e, and that should fix it.

I did, and it did, and everything I need looks perfectly fine now!

Thank you once more!
Robert

### 17. Re: Phix, numbers, printf, log10

Happy end, Hypatia 4.0 is here, with 18 digits integers and 15 digits floating-point accuracy. I wrote my own replacements for power(), sprintf(), to_number() and round(), and I think rounding is working the way it should now. In case anyone should be interested, we can talk about it. The "%e" fix was essential (thanks again, Pete!), and also never to forget to use / power(10, n) instead of * power(10, -n).

Btw, I have no idea how this happens, but in March Hypatia had 1387 downloads. No feedback whatever, though.

Robert

### 18. Re: Phix, numbers, printf, log10

RobertS said...

No feedback whatever, though.

I was one of them. Here's some feedback.

I'm running under Linux, specifically WSL hosting Ubuntu under Windows 11. This stackoverflow posting describes ways of getting the terminal's dimensions.

-Bruce

P.S. More to follow

### 19. Re: Phix, numbers, printf, log10

```bugmagnet@LAPTOP-H6HBEGA9:~/hypatia/source\$ ~/phix/p hy.exw
Hypatia RPN Calculator 3.3
? ?
?
For help use HELP command

I/O file location: program folder /home/bugmagnet/phix/
External editor:
Current screen width not available under Linux
Result format: decimal
Auto include \$: ON
Zero threshold: 1e-13
Max. number of passes in loop: 100000
Echo mode: OFF
Copy all results to clipboard: OFF
Logging: OFF
Buffer mode: OFF
```

### 20. Re: Phix, numbers, printf, log10

I found it a little counter intuitive to have hy.ini in the same folder as phix itself. But it's there now

-Bruce

### 21. Re: Phix, numbers, printf, log10

Hmmm ... no command line editing. And apparently then no history of commands. Or is it just that Hypatia hasn't been clued in to the relevant keystrokes?

-Bruce

### 22. Re: Phix, numbers, printf, log10

The sad fact is that I have no Linux experience whatever, have no Linux system that I could use for testing, and even if I had, I'd never know if I did things right. So, I'm glad to hear that at least you got Hypatia running!

axtens_bruce said...

This stackoverflow posting describes ways of getting the terminal's dimensions.

I'll take another look at it, but at first glance I don't understand how to use this within a Phix program. To know the window width would be helpful, but for the input editor I'd also need to be able to control the cursor (see below).

axtens_bruce said...

I found it a little counter intuitive to have hy.ini in the same folder as phix itself. But it's there now

It's not meant to be. I can only speak for Windows, but this happens when Phix runs the source code. The compiled hy.exe uses the program folder for input and output, unless you call it with the -c option, then it uses the current folder (but doesn't create an empty hy.ini if none exists). When you use Phix to run hy.exw, then cmd[1] returns the Phix folder as the program folder, so this is where hy.ini goes (and all other files will be written or read). Should you have compiled hypatia and it still uses the Phix folder, then this is a Linux issue that needs looking into.

axtens_bruce said...

Hmmm ... no command line editing. And apparently then no history of commands. Or is it just that Hypatia hasn't been clued in to the relevant keystrokes?

Doesn't work with Linux, at least not for now. The input editor needs video_config() for the screen width, but even more important are get_position() and position() for the cursor, and since they don't work under Linux, Hypatia doesn't even try - that is, under Linux it simply calls Phix's prompt_string() instead of my own prompt_string_ed(). Someone would have to tell me how to get and how to set the cursor location under Linux in a Phix program, if it can be done.

So, sorry, currently Hypatia and Linux don't go together very well, which is a pity, but I'd need help to do anything about it. Anyway, thank you for looking into it and for your feedback!

Robert

### 23. Re: Phix, numbers, printf, log10

And it looks like it's a problem for everyone: https://unix.stackexchange.com/questions/714209/get-cursor-location-in-tty-without-reading-from-stdin-need-help-with-redirectio

### 24. Re: Phix, numbers, printf, log10

RobertS said...

Doesn't work with Linux, at least not for now. The input editor needs video_config() for the screen width, but even more important are get_position() and position() for the cursor, and since they don't work under Linux,

Must be Phix specific? get_position() and position() work fine under OE iirc - though if memory serves correctly this is tied to ncurses (which Phix is not likely using).

I suspect that this is what ncurses does internally - on startup (before any user input has happened) set the position by writing to stdout. That way the position is at some known fixed value.

Use a state machine of some kind, so with every write to the screen, a variable gets updated with the current position.

When writing to the screen, prefix each write with the escape sequence to set the position - this minimizes sides from other processes writing on the terminal and changing the position behind our backs.

Finally, when getting the current position, consult the variable instead of asking the terminal. That way there's no issue of reading from stdin and losing data.

### 25. Re: Phix, numbers, printf, log10

jimcbrown said...
RobertS said...

Doesn't work with Linux, at least not for now. The input editor needs video_config() for the screen width, but even more important are get_position() and position() for the cursor, and since they don't work under Linux,

Must be Phix specific? get_position() and position() work fine under OE iirc - though if memory serves correctly this is tied to ncurses (which Phix is not likely using).

I suspect that this is what ncurses does internally - on startup (before any user input has happened) set the position by writing to stdout. That way the position is at some known fixed value.

Use a state machine of some kind, so with every write to the screen, a variable gets updated with the current position.

When writing to the screen, prefix each write with the escape sequence to set the position - this minimizes sides from other processes writing on the terminal and changing the position behind our backs.

Finally, when getting the current position, consult the variable instead of asking the terminal. That way there's no issue of reading from stdin and losing data.

I think the latest docs say everything that needs to be said: http://phix.x10.mx/docs/html/get_position.htm

The correct/easier way to properly solve this would be to write a test harness with (nb 1st upper) Print(), Printf(), Qu(), and Clear_Screen(), Position(), Put_Screen_Char(), and Display_Text_Image() shims, (that obviously pre-process their inputs to update some central position vars, with no real need for any low-level grubbiness, before invoking the real thing) with a Get_Position() that checks it would yield the same values as get_position(). It makes much more sense for someone working on Linux to write that on Linux (just as it makes much more sense for the person actually dealing with all that to actually care), and of course in Euphoria rather than Phix, since the whole point is to craft/test the code that would need to be added to the Phix builtins. Candidates with no formal qualifications in unicode and ncurses need not bother applying.

### 26. Re: Phix, numbers, printf, log10

petelomax said...

I think the latest docs say everything that needs to be said: http://phix.x10.mx/docs/html/get_position.htm

It says there, "fairly trivial for plain ascii" â€” for a plain ascii console app like Hypatia this would be good enough, if position() works, too. The width of the window could be found out by a loop that writes a row of spaces until cursor column is back to 1. If the width needs to be known in advance to keep track of the cursor, then let's stay with Windows ...

(I just don't understand, how can you write even the most simple user interface when your OS doesn't let you get a grip on the cursor?)

Robert