Weird problem with integer division, or is it me again?

Anything QL Software or Programming Related.
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Weird problem with integer division, or is it me again?

Post by NormanDunbar »

I'm loathe to say "bug" because it almost never is. But WTH am I doing wrong here?

I have an integer variable, in S*BASIC, and I'm dividing by another integer variable, with the result being assigned to a third integer variable. The idea is to take a value which is one of the two relative values returned by RPTR (in the S*BASIC toolkit), divide it by a given line depth to get the line number that the pointer was clicked at. Given a row depth of 12 pixels I'm seeing that row 0 is from pixels 0 to 5, row 1 is from pixels 6 to 18 and so on. The first row is bonkers!

Here's the minimal test code that shows the problem:

Code: Select all

1000 define procedure test(a%)
1010   local b%, c%
1020   b% = 10
1030   c% = a% / b%: print "a% / b% = "; c%,
1040   c% = INT(a% / b%): print "INT(...) = "; c%
1050 end define test
My test harness is as follows:

Code: Select all

for x = 0 to 10: y% = x: print y%;' = ': test(y%): end for x
And the results are:

Code: Select all

0 = a% / b% = 0 int(...) = 0
1 = a% / b% = 0 int(...) = 0
2 = a% / b% = 0 int(...) = 0
3 = a% / b% = 0 int(...) = 0
4 = a% / b% = 0 int(...) = 0
5 = a% / b% = 1 int(...) = 0
6 = a% / b% = 1 int(...) = 0
7 = a% / b% = 1 int(...) = 0
8 = a% / b% = 1 int(...) = 0
9 = a% / b% = 1 int(...) = 0
10 = a% / b% = 1 int(...) = 1
11 = a% / b% = 1 int(...) = 1
12 = a% / b% = 1 int(...) = 1
13 = a% / b% = 1 int(...) = 1
14 = a% / b% = 1 int(...) = 1
15 = a% / b% = 2 int(...) = 1
16 = a% / b% = 2 int(...) = 1
17 = a% / b% = 2 int(...) = 1
18 = a% / b% = 2 int(...) = 1
19 = a% / b% = 2 int(...) = 1
20 = a% / b% = 2 int(...) = 2
I was expecting the result of a pair of integers being divided and assigned to an integer, to be, an integer. Was I expecting too much? But it appears that this is only the case when I call INT() on the result.

When a% = 5 and b% = 10 for example, then a% / b% gives a result of 0.5 but when that gets assigned to c% it takes the value 1. It looks like it could be rounding the floating point value up to make an INT?

It's caused m,e no end of trouble today, I can tell you!


Any advice, corrections, explanations etc gratefully received. Feel free to hurl insults as well, if necessary! ;)

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
pjw
QL Wafer Drive
Posts: 1286
Joined: Fri Jul 11, 2014 8:44 am
Location: Norway
Contact:

Re: Weird problem with integer division, or is it me again?

Post by pjw »

If Ive understood your proposition correctly:

Integer division always rounds result to nearest integer, ie

c% = a% / b% is the same as c = INT(a / b + 0.5)

INT truncates the result, ie it returns the integer portion of the number ignoring the fractional part. Thus:

a% = 3: b% = 4: c% = a% / b%: c = a% / b%: PRINT c%, c, INT(a% / b%) produces
1, 0.75, 0


Per
dont be happy. worry
- ?
User avatar
dilwyn
Mr QL
Posts: 2753
Joined: Wed Dec 01, 2010 10:39 pm

Re: Weird problem with integer division, or is it me again?

Post by dilwyn »

A clue is given in Chapter 8 of the QL User Guide (page 39 in my copy). I don't have a SuperBASIC system to hand to check on a QDOS system, checking in SBASIC does seem to confirm it.
If you write:
LET count%=5.43
the value of count% will become 5. But on the other hand:
LET count%=5.73
will cause the value of count% to be 6. You can see that SuperBASIC does the best it can, rounding off to the nearest whole number.
Seems to confirm what Per was saying, about rounding to nearest whole number where coercion is used, rather than behaving like INT.

Having had a look at some of my short older BASIC programs, I have some INTs in places where you may think they are not required. Probably this is why, that I had noticed this behaviour before but never really considered it. I don't remember seeing it explicitly described other than this, although I seem to have been aware of it


User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Weird problem with integer division, or is it me again?

Post by NormanDunbar »

Thanks gents. I thought it was the rounding, looks like I got something right for once.

Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
User avatar
tofro
Font of All Knowledge
Posts: 2685
Joined: Sun Feb 13, 2011 10:53 pm
Location: SW Germany

Re: Weird problem with integer division, or is it me again?

Post by tofro »

#1: There's no integer arithmetic in S*BASIC - everything is done using the maths stack and FP. So, if you decide to store 2 variables in integers and divide one by the other, each of them will be converted to floating point and divided to get an FP result. That's weird, but that's how BASIC works.

#2 If you want to divide two integer variables, use DIV - It will still convert to FP first, and will still give a floating point result, but a more properly rounded one (DIV actually will return the floor value of the division), and on SBASIC, it will even support long integer division (In that case you need to give FP input for anything bigger than $ffff, however).

#3 if you want "real" integer division, use a compiler - Turbo or QLiberator will skip the FP conversion when they see an integer division with an integer result and use proper integer arithmetic.


ʎɐqǝ ɯoɹɟ ǝq oʇ ƃuᴉoƃ ʇou sᴉ pɹɐoqʎǝʞ ʇxǝu ʎɯ 'ɹɐǝp ɥO
User avatar
mk79
QL Wafer Drive
Posts: 1349
Joined: Sun Feb 02, 2014 10:54 am
Location: Esslingen/Germany
Contact:

Re: Weird problem with integer division, or is it me again?

Post by mk79 »

tofro wrote:#2 If you want to divide two integer variables, use DIV - It will still convert to FP first, and will still give a floating point result, but a more properly rounded one (DIV actually will return the floor value of the division), and on SBASIC, it will even support long integer division (In that case you need to give FP input for anything bigger than $ffff, however)
Actually that's not entirely true, at least in SBASIC integers are not stored as FP and the DIV command uses a single DIVS instruction if both operands are integers. Long integers are stored as FP, but in this case still a long integer division (cv_sldiv) is used, not a floating point div with floor.


User avatar
polka
Trump Card
Posts: 196
Joined: Mon Mar 07, 2011 11:43 am

Re: Weird problem with integer division, or is it me again?

Post by polka »

Hi !
All these are not bugs but "features". You should also explore the cases of negative divident or divisor or both.
In ComputerOne Forth (that within the standard should know only about integers and flooring division/modulus) there was here a real bug, the most serious one I found, but fortunately I could patch it.
POLKa


May the FORTH be with you !
POLKa
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Weird problem with integer division, or is it me again?

Post by NormanDunbar »

Afternoon all,

thanks for the information everyone. I'm just prototyping a new application in S*BASIC, and if it works, it will be converted to Assembly and turn up in a forthcoming issue of the somewhat irregular eComic. Because the final intention is assembly language, I'm not too worried about the integer to FP back to (the wrong!) integer "problem", now I know why it's happening.

DIV = "FLOOR" = INT = what I'm after. I do find it a tad weird that with all the support for DIV and INT that assignment to an integer does rounding. Still, I'm not Jan Jones, Tony Tebby, Marcel or Wolfgang et al, so what would I know? ;)

Right, back to coding. Thanks again.


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
Derek_Stewart
Font of All Knowledge
Posts: 3929
Joined: Mon Dec 20, 2010 11:40 am
Location: Sunny Runcorn, Cheshire, UK

Re: Weird problem with integer division, or is it me again?

Post by Derek_Stewart »

Hi,

Does it matter that the FOR loop index is not defined as an Integer?


Regards,

Derek
User avatar
NormanDunbar
Forum Moderator
Posts: 2251
Joined: Tue Dec 14, 2010 9:04 am
Location: Leeds, West Yorkshire, UK
Contact:

Re: Weird problem with integer division, or is it me again?

Post by NormanDunbar »

Hi Derek,
Derek_Stewart wrote:Hi,
Does it matter that the FOR loop index is not defined as an Integer?
Not really, as I assign the FOR loop index to an integer variable before calling the test code. FOR loop indexes on the original QL were floats anyway, I remember Turbo allowed them to be integers with IMPLICIT%, Minerva did too I think, but as I never had Minerva, I can't say for sure.

SMSQ also allows them, but my figers are still running in QDOS mode, so never types the % after the loop index name! ;)


Cheers,
Norm.


Why do they put lightning conductors on churches?
Author of Arduino Software Internals
Author of Arduino Interrupts

No longer on Twitter, find me on https://mastodon.scot/@NormanDunbar.
Post Reply