Modulus Divide - dropping leading zero

BCJKiwi

Senior Member
28X1 fw Ver A.1, Programming Editor 5.1.7

Have found an issue while testing which relates to the // operator.
Any leading zero(s) in the remainder or decimal portion is(are) dropped!!

e.g. a value of 5025 / 1000 with a calculator gives a result of 5.025
But PICAXE code;
5025 // 1000
produces an output of 25
where it should produce 025.

However the DIG command produces the correct results from the same source variable.
 

bgrabowski

Senior Member
Modulus divide simply returns the remainder. In your example 5025/1000 would produce 5 which accounts for 5000 of the initial 5025. Therefore 5025//1000 would produce the remainder after deducting 5000 ie 25.
 

hippy

Ex-Staff (retired)
It's not really a bug, just that it doesn't work the way you'd like it to.

The Modulus itself has no idea of how many leading zeros you think a result may have, and it actually has as many as you may ever want. Only when you come to display the number does the issue emerge, it's SERTXD(#var) not displaying the leading zeros you want rather than a problem with modulus ...

- b0 = 1000
- b1 = 0001
- SERTXD ( #b0 , "." , #b1 )

Displays "1000.1", not the "1000.0001" you'd like.
 

BCJKiwi

Senior Member
OK, I understand what is being explained.
However I don't really agree.

bgrabowski
The true result of the calculation 5025/1000 is not 5 but 5.025 - integer math results in this becoming 5 but the underlying number 5025 is there.
The true remainder of the sample calculation 5025//1000 is actually 025 not 25 - after all if if the starting number is 5125, the remainder is 125, not 25.
The issue is that the leading zero is dropped in the calculation before it gets to the display. This can be verified in the simulator.

Hippy
your example deals with the display issues but with the // operator, the problem is in the math, before it gets to the display - as above - this is verified in the simulator

I guess we have to work with what we have so I suggest the explanation in the manual be improved to cover this as when looking at the way many people use this function in their programs they have fallen into the same trap!

e.g. Hippy, your code snippet;
Code:
Symbol Nref = b0
Symbol Nadc = b1
Symbol Vadc = b2
Symbol Vdec = b3
CalibAdc Nref
ReadAdc 1, Nadc
Vadc = Nadc * 6 / Nref / 10
Vdec = Nadc * 6 / Nref // 10
SerTxd( "Voltage = ", #Vadc, ".", #Vdec, "V", CR, LF )
Only works correctly as it only outputs one decimal place but if you were attempting to display 2 decimal places (Vdec = Nadc * 60 / Nref // 100) it would produce errors.

So what is the workaround (if you don't have an X1 that supports DIG)?
How could 5025 be displayed as 5.025?

OK just discovered (a case of serendipity) your post #8 here;
http://www.picaxeforum.co.uk/showthread.php?t=8092
Code:
Watch out if going to two or more digits after the decimal point ...

- w0 = value / 1000
- w1 = value // 1000
- SerTxd( #w0, ".", #w1, CR, LF ) ' Display X.YYY

Leading zeroes get dropped in #w1 so a value of 1001 will end up incorrectly reported as "1.1", not as "1.001".

To get round that it becomes necessary to force those leading zeroes to be reported separately ...

- w0 = value / 1000
- w1 = value // 1000
- SerTxd( #w0, "." )
- If w1 < 100 Then : SerTxd( "0" ) : End If
- If w1 < 10 Then : SerTxd( "0 ") : End If
- SerTxd( #w1, CR, LF )

An arguably more elegant version ( but probably with slightly larger code size ) would be -

- w0 = value / 1000
- w1 = value // 1000
- SerTxd( #w0, "." )
- Select Case w1
--- Case < 100 : SerTxd( "00" )
--- Case < 10 : SerTxd("0")
- End Select
- SerTxd( #w1, CR, LF )

The best way to save code space if you have a number of decimal numbers to display is to put that code in a subroutine and call it as needed.
Thanks - nothing new under the sun
 
Last edited:

lbenson

Senior Member
>The true remainder of the sample calculation 5025//1000 is actually 025 not 25

That's not the way that the modulus operator works in any language, and more fundamentally, not the way that binary representation of integers works. There is nothing in the binary representation of, say, 25 (%00011001) to indicate that you want that value to represent 25 hundredths or 25 thousandths or 25 millionths. That is a characterization which you must maintain through other manipulations in your code, and unfortunately, when you go to display fractional numbers in an integer-only coding system, you have to supply the code which inserts the proper number of leading zeros after the decimal point.
 

BCJKiwi

Senior Member
Agreed, that is not the way it works In PICAXE basic and is also the case in most (but not actually all) programming languages, but that is not actually the way it should be. Its a convention of programming language developers, now near universal.

>The true remainder of the sample calculation 5025//1000 is actually 025 not 25
A study of the true definition of modulus indicates it should return everything after the decimal - which includes any leading zero.

However, we may never agree, and I accept it won't be changed by Rev-Ed because they are (rightfully) following standard programming.

The point I'm trying to make by continuing this discussion is that it does not work the way most (who do not have in-depth programming experience) would expect it to, and we need to know that and how to get the result we expect - hence the comment about a change to the documentation.
 
Last edited:

hippy

Ex-Staff (retired)
>The true remainder of the sample calculation 5025//1000 is actually 025 not 25
A study of the true definition of modulus indicates it should return everything after the decimal - which includes any leading zero.
That opens up another whole issue - What decimal ???

w0 = 10002 // 10 = 2
w0 = 10002 // 100 = 02
w0 = 10002 // 1000 = 002
w0 = 10002 // 10000 = 0002

You're only imagining a decimal point and the // N implies it only to a human reader, // 50 is equally valid for // so where's the decimal there ?

In each case the remainder is 2, so how would w0 store the different versions of 2 with the right number of leading zeros ?

I haven't tried the simulator, but if it's holding onto and showing leading zeros then I'd say that was a flaw in the simulator, and it has misled you.

If you're familiar with "old numbers", an excess measurement over an inch, measured in thousandths of an inch ... 1020 // 1000 is "20 thousandths of an inch" too big, people wouldn't say or write "020 thousandths"; so // behaves as an engineer would.
 

hippy

Ex-Staff (retired)
The point I'm trying to make by continuing this discussion is that it does not work the way most (who do not have in-depth programming experience) would expect it to
I accept that's probably correct, people do expect things to work which don't ( or can't ), and only experience makes one know otherwise.

That's one of the arguments why only professionals should be allowed to code, amateurs should stay well clear of what they don't understand, and why some people get twitchy whenever a safety critical project arises ;-)

I'll put my own hand up to using SERTXD(#b0,".",#b1) and wondered where the leading zeros had gone before a D'Oh! moment, and I know of others who have done that as well.

Another challenge for the human mind is negating a 16-bit two's complement signed value of -32768, that's $8000 in hex :)
 

BCJKiwi

Senior Member
Hippy, re your post #7
The simulator drops the leading zeros - see my post #4

I would have thought your post #7 made my case.
The table clearly shows that as you change the modulus you change the number of zeros - the modulus defines the decimal position.

As for the engineer's approach, that is exactly the same. Saying 20 thou is the way the number of leading zeros is indicated ie. 20 thou means 20 / 1000, ie shift the decimal left three places.
 
Last edited:

Technical

Technical Support
Staff member
bcjkiwi-
One key point you are missing is that the value in the w1 variable is just a number between 0-65535 to the 'sertxd' command. The sertxd command has no idea what the source/history of that number was - ie. whether w1 is the result of a modulus equation or not - it is just a number as far as sertxd is concerned.

Therefore sertxd cannot decide whether to add leading zeros or not in this specific case. This has to be accounted for by the user program.
 

BCJKiwi

Senior Member
Sertxd is not the issue. The result of the modulus command has already dropped the leading zero(es) - at least it does in the simulator.
 

hippy

Ex-Staff (retired)
That's right, but leading zeroes for integer numbers are an artificial construct. Any integer number can have none to an infinite number of leading zeroes depending upon how you want to imagine it to be. A computer doesn't have any idea what you are imagining or would like; it stores 1, 01, 001, 0001 etc all as 1, and has no concept of any difference.
 
Top