Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 12:03 11 May 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : [MMBasic] 7 Digit Numeric Precision

Author Message
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 03:52am 20 Jul 2014
Copy link to clipboard 
Print this post

Hi

Last Friday, @JohnS, showed me how to get at the hidden 7th digit of MMBasic numeric vars - thank you @JohnS. I thought that @JohnS' insight was very worthwhile sharing with a wider audience.

Try this


Print PI


MMBasic will display


3.14159


Now try this instead


Print int(pi);".";str$((pi-int(pi))*1000000)


MMBasic will display


3.141593


ie 7 digit precision

And here's @JohnS' original proof of the 7th digit and how to get at it.


x = 999999 + 999999

IF x < 1000000 THEN
PRINT x
ELSE
PRINT x \ 1000000;
PRINT STR$(x - (x \ 1000000) * 1000000 )
ENDIF


Run it and MMBasic will print


1999998


That's 7 digits, and MMBasic hasn't switched into exponential notation, eg 2.00000e+06

73

Peter
The only Konstant is Change
 
BobD

Guru

Joined: 07/12/2011
Location: Australia
Posts: 935
Posted: 07:09am 20 Jul 2014
Copy link to clipboard 
Print this post

  G8JCF said  
Now try this instead


Print int(pi);".";str$((pi-int(pi))*1000000)




It's only small stuff but as well as 7 digits you are trying to get speed and it all helps. I seem to recall that you can knock out the semi-colons (;) in the above and still get the desired result.


Print int(pi)"."str$((pi-int(pi))*1000000)


However, you can't do that for one at the end of a line.

Bob
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 07:43am 20 Jul 2014
Copy link to clipboard 
Print this post

All I did was to note the 16777100 and suspect there'd be 7 (and a little bit more) digits.

I've just made a little test using the PIC32/MIPS32 C32 (gcc) and it looks like the biggest integer that's exact is 16777215 (or 16777216 but that happens to be an exact power of 2), i.e. 0xffffff or 24 bits.

I'm cheating really, as I've used a considerable number of floating point systems over the years and though they tend to vary somewhat they're also much alike - and you pick things like this up. Occasionally it's actually useful!

You might like to read up on things like "machine epsilon"...

John
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 09:47am 20 Jul 2014
Copy link to clipboard 
Print this post

@JohnS

Great insight, all those years at the FP coalface :). BTW, I wouldn't call it cheating, you just a very good programmer's nose.

Anyway, thanks to your insight, I will be able to release an arbitrary precision arithmetic library which should run reasonable quickly, eg less than 2 mS for an 18 digit add/sub @ CPU 48, and it does include Mul & Div because moving/marshalling the numbers between sextet BCD packing, ie 6 decimal digits/numeric var and triplet BCD packing, ie 3 decimal digits/numeric var is very simple. I've had the triplet BCD packing arith. lib done and dusted for over a month now but was trying to squeeze more performance out for the AD9850Controller project.

Take care

Peter
The only Konstant is Change
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 09:52am 20 Jul 2014
Copy link to clipboard 
Print this post

@BobD

Thanks for that tip. The only downside of using undocumented features such as this print trick, is that some future version of MMBasic might tighten up on the Syntax checking and break the code, but still worth knowing.

Thanks

Peter
The only Konstant is Change
 
BobD

Guru

Joined: 07/12/2011
Location: Australia
Posts: 935
Posted: 09:55am 20 Jul 2014
Copy link to clipboard 
Print this post

It was a tip announced by GeoffG recently. Sorry I can't refer back to his post. Searching this board can be difficult without a good key word.
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 12:03pm 20 Jul 2014
Copy link to clipboard 
Print this post

Hi

This might prove useful for displaying large numbers without swithing into exponent notation - useful for frequency displays mainly I would imagine. Best precision is 7 digits, for 10 MHz and above, zeroes are appended to the figure as appropriate.

I needed this for the AD9850 controller frequency display but it might be useful elsewhere. (I just hope there's not a bug lurking in there !)

73

Peter




'=========================================================
'
' Function which extends the functionality of the native
' STR$() function
'
' If Number < 1,000,000 then 6 digit precision using native STR$()
' If 999,999 < Number < 9,999,998 then 7 digit precision result
' If 9,999,998 < Number < 100,000,00 then 7 digit precision result with 1 Zero appended
' If 99,999,999 < Number < 999,999,968 then 7 digit precision with 2 zeroes appended
' If 999,999,967 < Number then 6 digit precision using native STR$()
'
'
FUNCTION StrEx$(Number,M,N,C$)

'Is Number small enough to use normal STR$ ?
IF Number < 1000000 THEN
StrEx$=STR$(Number,M,N,C$)
EXIT FUNCTION
ENDIF

'We have a big enough number such that 7 digit precion is useful

IF C$="" THEN C$="0"
IF M<1 THEN M=6
IF N<1 THEN N=0
Exponent=VAL(RIGHT$(STR$(Number),2))

IF Number<9999999 THEN
StrEx$=MID$(STR$((Number)\1e6)+STR$(Number-((Number)\1e6)*1e 6,6,N,C$),1,7)
EXIT FUNCTION
ENDIF

IF Number<100000000 THEN '99999999 THEN
StrEx$=MID$(STR$((Number+5)\1e6)+STR$(Number+5-((Number+5)\1 e6)*1e6,M,N,C$),1,7)+STRING$(Exponent-6,"0")
EXIT FUNCTION
ENDIF

'It should be 1000,000,000 but MMBasic errors out with "Number is too large"
IF Number<999999968 THEN
StrEx$=MID$(STR$((Number+50)\1e6)+STR$(Number+50-((Number+50 )\1e6)*1e6,M,N,C$),1,7)+STRING$(Exponent-6,"0")
EXIT FUNCTION
ENDIF

'Just return it in exponent form
StrEx$=STR$(Number)

END FUNCTION


The only Konstant is Change
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6220
Posted: 01:24pm 20 Jul 2014
Copy link to clipboard 
Print this post

You can use STR$ to show the full precision on the micromite.
(Maximites use FORMAT for similar results)

print PI
print str$(PI, 2,4)
print str$(PI, 2,5)
print str$(PI, 2,6)
print str$(PI, 2,7);" We have gone over the true precision level of 32bit here"


Jim
VK7JH
MMedit
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 01:37pm 20 Jul 2014
Copy link to clipboard 
Print this post

Hi Jim

I tried this as part of the investigations but

print str$(PI, 2,6)

produces the incorrect result, it should be 3.141593 but instead it produces 3.141592

Print int(pi);".";str$((pi-int(pi))*1000000) produces the correct answer of 3.141593

PI (according to my HP35s) is 3.14159265359, so to 6 significant places that should be 3.141593.

So is there a bug in STR$(), ie not rounding properly when the number of decimal places is specified at 6 ?

It's fascinating where the quest for greater arithmetic precision is taking the conversation - I've discovered (re) a whole world of stuff I'd forgotten since I was first at University 40 years ago !

73

Peter






The only Konstant is Change
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 02:04pm 20 Jul 2014
Copy link to clipboard 
Print this post

PS, does FORMAT$ on a MaxiMite give the correct result of 3.141593 ?
The only Konstant is Change
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6220
Posted: 02:14pm 20 Jul 2014
Copy link to clipboard 
Print this post

Peter,
Due to the limit of 32 bit precision, the maximite value for PI ends up as 3.1415925
This unfortunately (for PI perfectionists) results in it getting rounded to 3.141592 rather than 3.141593 which is the more correct value.

It is all due to 32bit floating point limitations. If the maximite used 64bit floating point, there would still be limitations and strange results.

You can test the maximite syntax using DOS MMBasic.
A while ago when I did some testing I did find that there were differences between maximite and DOS when you pushed the boundaries. This was probably due to the different C compilers used.

Jim

VK7JH
MMedit
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 02:37pm 20 Jul 2014
Copy link to clipboard 
Print this post

Hi Jim

Print format$(PI,"%f")

in MMBasic for DOS produces the correct answer of 3.141593

So it looks (to me) that STR$() (uMIte) may have a bug in that STR$() (uMIte) because it is not rounding correctly.

interestingly, in uMite, do

A=1.2345675
Print STR$(A,2,6)

and the correct answer is printed, ie

1.234568

Perhaps Geoff knew about these inconsistencies when he chose to limit MMBasic's PRINT statement to output 6 digit precision ?

Puzzled.

Peter




The only Konstant is Change
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6220
Posted: 05:16pm 20 Jul 2014
Copy link to clipboard 
Print this post

Try this code on the different platforms:

PRINT MM.DEVICE$
IF MM.DEVICE$="Micromite" THEN
PRINT PI
PRINT STR$(PI, 2,4)
PRINT STR$(PI, 2,5)
PRINT STR$(PI, 2,6)
PRINT STR$(PI, 2,7)
PRINT
PRINT 3.1415926
PRINT STR$(3.1415926, 2,4)
PRINT STR$(3.1415926, 2,5)
PRINT STR$(3.1415926, 2,6)
PRINT STR$(3.1415926, 2,7)
PRINT
PRINT 3.14159265358979
PRINT STR$(3.14159265358979, 2,4)
PRINT STR$(3.14159265358979, 2,5)
PRINT STR$(3.14159265358979, 2,6)
PRINT STR$(3.14159265358979, 2,7)
PRINT
PRINT 3.14159265358979323846
PRINT STR$(3.14159265358979323846, 2,4)
PRINT STR$(3.14159265358979323846, 2,5)
PRINT STR$(3.14159265358979323846, 2,6)
PRINT STR$(3.14159265358979323846, 2,7)
ELSE
PRINT PI
PRINT FORMAT$(PI, "%7.4f")
PRINT FORMAT$(PI, "%8.5f")
PRINT FORMAT$(PI, "%9.6f")
PRINT FORMAT$(PI, "%10.7f")
PRINT
PRINT 3.1415926
PRINT FORMAT$(3.1415926, "%7.4f")
PRINT FORMAT$(3.1415926, "%8.5f")
PRINT FORMAT$(3.1415926, "%9.6f")
PRINT FORMAT$(3.1415926, "%10.7f")
PRINT
PRINT 3.14159265358979
PRINT FORMAT$(3.14159265358979, "%7.4f")
PRINT FORMAT$(3.14159265358979, "%8.5f")
PRINT FORMAT$(3.14159265358979, "%9.6f")
PRINT FORMAT$(3.14159265358979, "%10.7f")
PRINT
PRINT 3.14159265358979323846
PRINT FORMAT$(3.14159265358979323846, "%7.4f")
PRINT FORMAT$(3.14159265358979323846, "%8.5f")
PRINT FORMAT$(3.14159265358979323846, "%9.6f")
PRINT FORMAT$(3.14159265358979323846, "%10.7f")
ENDIF

'MicroMite:
'
'// Return the value of Pi. Thanks to Alan Williams for the contribution
'void fun_pi(void) {
' fret = (float)3.1415926;
'}
'
'Maximite:
'
'// Return the value of Pi. Thanks to Alan Williams for the contribution
'void fun_pi(void) {
' fret = (float)3.14159265358979323846;
'}
'


The results are:
  Quote  DOS output:

DOS
3.14159
3.1416
3.14159
3.141593
3.1415925

3.14159
3.1416
3.14159
3.141593
3.1415925

3.14159
3.1416
3.14159
3.141593
3.1415927

3.14159 323846
[48] Print Format$(3.14159265358979323846, "%7.4f")
Error: Incorrect expression syntax
>

Maximite output:

Maximite
3.14159
3.1416
3.14159
3.141592
3.1415925

3.14159
3.1416
3.14159
3.141592
3.1415925

3.14159
3.1416
3.14159
3.141593
3.1415927

3.14159 323846
[48] Print Format$(3.14159265358979323846, "%7.4f")
Error: Incorrect expression syntax
>


MicroMite output:

MicroMite
3.14159
3.1416
3.14159
3.141592
3.1415925

3.14159
3.1416
3.14159
3.141592
3.1415925

3.14159
3.1416
3.14159
3.141593
3.1415927

3.14159 323846
[23] Print Str$(3.14159265358979323846, 2,4)
Error: Incorrect expression syntax
>


Even though the Maximite and MicroMite have different values for PI, the output is identical for both the PIC32 versions.

The DOS version is compiled with an entirely different compiler which is why you see differences.
It is always dangerous when you are pushing the limits of precision. The plain PRINT x is playing save and gives a reasonably true indication of the available precision.

In all cases, if you try and enter a very long number, strange things happen.

Jim


VK7JH
MMedit
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 01:45am 21 Jul 2014
Copy link to clipboard 
Print this post

So Jim

I understand your point I think.

From your Output prints, it seems to me that only the DOS MMBasic is carrying out proper rounding from 6 digit to 4 digit precision, all the other versions seem to chop off digits when using STR$().

What are the takeaway(s) from this then ?

Are there any ?

If so on the Maximite & uMite could these be they ?

1) Avoid STR$() with N > 5

2) If you need 7 digit precision then use something like Print int(pi);".";str$((pi-int(pi))*1000000)

3) Avoid 6 decimal places if using STR$()

73

Peter


The only Konstant is Change
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 04:09am 22 Jul 2014
Copy link to clipboard 
Print this post

Some of those may be hitting the issue of precision, roughly meaning the number of significant digits that can be represented (stored).

There might also be an issue with the conversion from the program source into the internal (binary, if you like) representation.

John
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 09:16am 22 Jul 2014
Copy link to clipboard 
Print this post

Hi John, Jim

Could it be that the DOS version of MMDos is using the H/W FPU built into Intel processors to do its SINGLE floating point arithmetic ? If so then I think that might explain why MMBasic on DOS is more correct than the other platforms since the Intel FPU has been really, really well designed and complies completely in all respects with the IEEE specifications for floating point implementations. (I mean given the billions of CPU's Intel has sold, if their FPU was deficient in any way (yes there was that Pentium bug which was the result of 5 lookup table entries in the silicon being incorrect !) we would have heard all about it, and they would have fixed it.) Having said all that, I could be completely barking up the wrong tree of course. I suppose the IEEE must have a test suite of operations with values which any system which purports to implement their floating point standard - IEEE 754 - must be able to demonstrate compliance with (MMBasic doesn't make that claim afaik)?

73

Peter
The only Konstant is Change
 
JohnS
Guru

Joined: 18/11/2011
Location: United Kingdom
Posts: 3998
Posted: 09:26am 22 Jul 2014
Copy link to clipboard 
Print this post

If I could run the DOS version I could find out! But it's an NT windows console app by the looks of it and Linux WINE doesn't seem happy with it.

I can run the Linux MMBasic OK and that appears to have the same fp as the PIC32 from a not very long test.

Could easily be using the IEEE754 stuff which as you say is generally excellent (I still have the full spec, how sad is that).

Oh, the CPU bug... I recall the hassle Intel got but they did eventually offer to swap the chips (I was working for a computer maker at the time).

Don't suppose you know G4CLI?

John
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 10:20am 22 Jul 2014
Copy link to clipboard 
Print this post

Hi John

Unfortunately I haven't yet come across G4CLI - he's only 7 months older than me ! Why ? I operate on 40m and 20m with 100W from an IC-7200, but since I've gotten hold of these uMites, I've not been on the air at all

Have U got VMWare ? If so U could then run Windows in a VM under LINUX with XP (XP is pretty much free these days) and that way try out various Windows only s/w perhaps. I do it the other way round, I run Windows 64 with 8 GB of RAM and then have Debian VMs under VMWare (all free stuff).

Did U have to implement an IEE754 library ?

Peter




The only Konstant is Change
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025