Qbasicnews.com

QBasic => QB Discussion & Programming Help => Topic started by: Moneo on July 14, 2003, 01:40:49 PM



Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 01:40:49 PM
The following anomaly occurs in QuickBasic 4.5. Does anyone know why this happens?
Code:

DEFLNG a-z
dim a as integer
dim n as integer

n = 128

rem The following two instructions work perfectly:

a=log(n)/log(2)
if 2^a = n then print n, "is a power of 2"

rem The following instruction, which is a combination of the above, DOES NOT WORK.

if 2^(log(n)/log(2)) = n then print n, "is a power of 2"

I don't understand. Why does it work separately but not combined?
Thanks.
*****


Title: HELP: Why does this not work?
Post by: na_th_an on July 14, 2003, 01:44:15 PM
Dunno, but maybe the result of log(n)/log(2) isn't integer, hence the error.

a is integer, so a = log(n)/log(2) will perform an implicit INT(log(n)/log(2)), and, generally:

Code:
2^INT(log(n)/log(a))    <>    2^(log(n)/log(a))


Check it out :)


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 02:23:06 PM
Nathan,
Your analysis makes perfect sense.
So if I changed the failing instruction as follows, it should work.

if 2^INT(log(n)/log(2)) = n then print n, "is a power of 2"

WELL, IT DOES NOT WORK. ????
Any ideas?
*****


Title: HELP: Why does this not work?
Post by: na_th_an on July 14, 2003, 02:24:25 PM
Well, this time I HAVE NO CLUE!!  :???:  Another QB bug?


Title: It works fine for me for n up to 8192...
Post by: Glenn on July 14, 2003, 02:49:56 PM
It fails at n = 16384.  However, changing INT to CINT makes it work for 16384.  (CINT converts to INTEGER and rounds correctly.  INT just truncates.)


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 02:55:26 PM
Glenn,
If I put into a loop, it also works up to 1024,
EXCEPT THAT 128 DOESN'T WORK.

When n=128, the one line combined instruction does not work with or without the INT.
If I round the result inside the parentesis, it will work. But why do I need to do this when all the other numbers work without it?
*****


Title: What's really happening is that digital computers...
Post by: Glenn on July 14, 2003, 03:04:51 PM
don't store floating point numbers accurately (and LOG returns a floating point result).  When n = 128, LOG(n) / log(2) should be 7 but what you get is something slightly less than 7.  Similarly, if n = 16384, the result should be 14 but you get something slightly less than 14.  So, INT truncates the result to 6 or 13.   For the other values, you get a result slightly above the integer that math says you should get and so INT's truncation works.  Instead of using CINT, the perhaps more insightful solution is to use

INT(LOG(n) / LOG(2) + .001)


Title: HELP: Why does this not work?
Post by: Agamemnus on July 14, 2003, 03:38:45 PM
or just use code to get the max bits used.


Title: Used in what, the right value or the wrong one?...
Post by: Glenn on July 14, 2003, 03:45:06 PM
That right value isn't known a priori.  He's in fact using code to get the number of bits used.


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 03:46:13 PM
Quote from: "Agamemnus"
or just use code to get the max bits used.

Sorry, I don't know what you mean.
*****


Title: HELP: Why does this not work?
Post by: Agamemnus on July 14, 2003, 03:59:43 PM
128 uses 7 bits. 127 uses 7 bits. If 127 is less than 128, 127 isn't a power of 2.


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 04:08:45 PM
Quote from: "Agamemnus"
128 uses 7 bits. 127 uses 7 bits. If 127 is less than 128, 127 isn't a power of 2.

I agree with your analysis, but how do I apply it to solving my posted problem?
*****


Title: Agamemnus, your intuitive grasp of the obvious is...
Post by: Glenn on July 14, 2003, 04:11:50 PM
truly amazing.  :)


Title: HELP: Why does this not work?
Post by: Agamemnus on July 14, 2003, 04:20:45 PM
because 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 and 16384 are all powers of two, and code (that I forgot) that gets the max bits used for a number (how many bits are needed to represent it) that is then subtracted from 2^those bits (or the array in the beginning) if equals zero, then it is a power of two.

Or, do this:

Code:

sub power.of.two% (n%):
select case n%
case 2, 4 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
power.of.two% = -1
end select
end function


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 06:19:56 PM
AGAMEMNUS,
I know you're tying to help, but I'm not looking for alternate ways of determining if a number is a power of 2. I can already do that in the following 2 lines:
Code:

DEFLNG a-z
dim a as integer
dim n as integer

a=log(n)/log(2)
if 2^a = n then print n, "is a power of 2"

My problem is that I wanted to do it one line of code like this:
Code:
if 2^(log(n)/log(2)) = n then print n, "is a power of 2"

But, for some reason it doesn't work when n=128.
The purpose of my post was to ask why this doesn't work. Nathan had a good idea, but it didn't solve the problem.
*****


Title: HELP: Why does this not work?
Post by: Agamemnus on July 14, 2003, 06:26:34 PM
Glenn did. LOG(n) converts N to a float, which iis inaccurate.


Title: HELP: Why does this not work?
Post by: Sterling Christensen on July 14, 2003, 06:54:57 PM
I don't see what the problem is with Glenn's original idea of using CINT instead of INT. It works perfectly for me.
Code:

INPUT n%  ' notice that n% is an integer

' 2^(a positive integer) must produce an integer, and the variable
'    we're comparing it to is also an integer (n%), so we can assume
'    there will be no floating point error in comparison here:
IF 2 ^ CINT(LOG(n%) / LOG(2)) = n% THEN PRINT n%;"is a power of 2"


I tried every power of 2 from 1 to 16384 and it correctly identified each as a power of 2. Other numbers were ignored.


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 07:12:28 PM
You're right, Aga, Glenn's explanation regarding the fact that LOG gives a floating point result, basically answers my question.

However, if for n=128 the result of log(128)/log(2) is slightly less than 7, then why if you do:
a%=log(128)/log(2)
does it convert this result which is slightly less than 7, to a 7 which it puts into a%?

In other words, this result which is slightly less than 7 is treated as a 7 in one case, and not a 7 when I do all on one line.
THIS IS WHAT BUGS ME!

Somehow Basic is deciding how close a number has to be for it to ROUND it to an integer.
*****


Title: HELP: Why does this not work?
Post by: Agamemnus on July 14, 2003, 07:44:41 PM
I understand you now.

Code:

CLS
a# = LOG(128) / LOG(2): PRINT INT(a#)      'why doesn't this round down?
IF INT(a#) = 7 THEN PRINT "???"
a# = LOG(128) / LOG(2) - .000000001#: PRINT INT(a#); a#
a# = INT(LOG(128) / LOG(2)): PRINT a#
PRINT LOG(4045)


Something in the code smells funny...

Data: LOG() returns a single..


Title: HELP: Why does this not work?
Post by: oracle on July 14, 2003, 07:50:53 PM
I made a rounding program to correct the rounding but. It's available in the FAQ.


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 07:59:09 PM
You're right, Aga, something smells funny.
*****


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 08:03:49 PM
Oracle,
Where is this FAQ re rounding? I also looked in QBNZ and couldn't find it there either.
*****


Title: HELP: Why does this not work?
Post by: na_th_an on July 14, 2003, 08:38:59 PM
There is a link in the top side of this forum, just below "Back to QbasicNews.com" and next to "QBOHO".

http://faq.qbasicnews.com


Title: HELP: Why does this not work?
Post by: oracle on July 14, 2003, 08:50:58 PM
The FAQ definately needs more promoting. I'm promoting it at QBNZ, but I think an admin should update the front page and add a link to it down the LHS.


Title: HELP: Why does this not work?
Post by: Moneo on July 14, 2003, 10:10:36 PM
Found it. But what heading is it under?
*****


Title: HELP: Why does this not work?
Post by: oracle on July 14, 2003, 10:16:41 PM
http://faq.qbasicnews.com/?blast=RoundingNumbers

It's under misc.


Title: That's nice. Now include every power of 2 that exists...
Post by: Glenn on July 14, 2003, 10:28:40 PM
in your list of cases.  (Have a good time.)

Quote from: "Agamemnus"
because 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 and 16384 are all powers of two, and code (that I forgot) that gets the max bits used for a number (how many bits are needed to represent it) that is then subtracted from 2^those bits (or the array in the beginning) if equals zero, then it is a power of two.

Or, do this:

Code:

sub power.of.two% (n%):
select case n%
case 2, 4 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
power.of.two% = -1
end select
end function


Title: Basic doesn't have a monopoly on such fun and games...
Post by: Glenn on July 14, 2003, 10:33:28 PM
I've been playing those fun and games with fortran since before some people here have been born.  (I also have fun, for example, taking the arccos of numbers that can't possibly be larger than one, but yet...are.)   :)    It's caused by something that transcends specific programming languages or compilers.


Quote from: "Moneo"
You're right, Aga, Glenn's explanation regarding the fact that LOG gives a floating point result, basically answers my question.

However, if for n=128 the result of log(128)/log(2) is slightly less than 7, then why if you do:
a%=log(128)/log(2)
does it convert this result which is slightly less than 7, to a 7 which it puts into a%?

In other words, this result which is slightly less than 7 is treated as a 7 in one case, and not a 7 when I do all on one line.
THIS IS WHAT BUGS ME!

Somehow Basic is deciding how close a number has to be for it to ROUND it to an integer.
*****


Title: HELP: Why does this not work?
Post by: Moneo on July 16, 2003, 05:58:11 PM
Quote from: "oracle"
http://faq.qbasicnews.com/?blast=RoundingNumbers

ORACLE,
In your ROUND function, I would include a test if the input number is negative, and if so round by -.5
Don't you agree?
*****


Title: HELP: Why does this not work?
Post by: oracle on July 16, 2003, 08:39:08 PM
Done :)

Did it work for your ^2 program?


Title: HELP: Why does this not work?
Post by: Moneo on July 16, 2003, 09:19:59 PM
Quote from: "oracle"
Did it work for your ^2 program?


The results of my power of 2 program is that it works fine if you do it with 2 lines of code. I have a version of the one line of code which takes an INT and rounds by .5, but I can't justifiy doing all this just to make it work. In short, I don't trust it. If I had to do this in a production program I would definitely resort to doing it in 2 lines of code.

Thanks for your interest and support.
*****


Title: HELP: Why does this not work?
Post by: Antoni Gual on July 25, 2003, 06:01:39 AM
Moneo:
Probably the answer to your initial question is qb is using an increased precision in intermediate results. If you store the value in a variable it is rounded to the standard precission.

This thread gave me the idea
http://http://forum.qbasicnews.com/viewtopic.php?t=3455
Jark is using in his help the same "feature" that gives you problems


Title: INT and CINT
Post by: Jark on July 25, 2003, 12:21:43 PM
Slightly out of scope, but related anyway:

I unfortunately don't have a example of cases where the issue occurs, but I decided months ago to use INT(x!+.5) instead of CINT. I noticed some problems with CINT, and I got rid of them with this old trick...


Title: HELP: Why does this not work?
Post by: Flexibal on July 25, 2003, 12:56:43 PM
i have to say that

if 2^(log(n)/log(2)) = n then print "cuss word"

works for me.





[Flexibal>


Title: HELP: Why does this not work?
Post by: Moneo on July 25, 2003, 03:54:47 PM
ANTONI,
Thanks. I looked at the thread you mentioned, and like you said: "It's curious!" That is, QB uses one value in an internal calculation, but changes it if you store it into a variable. That is the root of the problem.

JARK,
At least 10 years ago I too discovered some weirdness with CINT. I don't remember exactly what it was, but since then I never use CINT at all. Must be the problem you mention.

FLEXIBAL,
No, the following "if" does not result true if n=128.
if 2^(log(n)/log(2)) = n then .....

That was the whole issue of this thread.
*****


Title: I hope that I am not stating the obvious.
Post by: SCM on August 01, 2003, 04:05:28 AM
Maneo,
I tried your procedure in MatLab and it worked fine.  There is an error in BASIC in the 20th digit of LOG(128)/LOG(2).  This also results in an error in the 20th digit of 2^(LOG(128)/LOG(2)).  Why BASIC doesn't consider 127.999999999999999951 the same as 128 I don't know (even in double precision any difference beyond the 16th digit should be neglected), but your two line code compensates for this by rounding 6.99999999999999999957 to 7 when it assigns it to a.  I think you'll have to be content with a two line procedure that works perfectly.


Title: HELP: Why does this not work?
Post by: Moneo on August 01, 2003, 03:51:18 PM
Thanks, SCM. Yeah, I'll have to use 2 lines of code.
*****


Title: HELP: Why does this not work?
Post by: xhantt on August 08, 2003, 04:29:46 AM
This message is too late but ...

Quote

dim a as long
input a
if (a>0) and ((a and (a-1))=0) then print a; " is a power of 2"


Title: HELP: Why does this not work?
Post by: Moneo on August 08, 2003, 03:29:46 PM
XHANTT:

It's never too late for an absolutely brillant and simple solution!

We all now have an excellent one-line algorithm for determining if a number is a power of 2. Thanks.

The logic is the same as when we want to cycle throught a range of numbers from 0 to a power of 2, minus 1. After incrementing, instead of doing an "if" to see if at the limit, you just "and" with the limit (power of 2, minus 1) and the cycle automatically begins with zero again. Many of us have seen this logic, but it never occurred to us to use it for determining powers of 2.
*****


Title: HELP: Why does this not work?
Post by: xhantt on August 08, 2003, 09:01:27 PM
I've to apologize, this piece of code is not my, it's from "c snippets".


Title: HELP: Why does this not work?
Post by: Moneo on August 09, 2003, 01:45:15 AM
XHANTT,
No need to apologize. You recognized an excellent solution and posted it for us. It's not important where it comes from.
*****


Title: HELP: Why does this not work?
Post by: oracle on August 11, 2003, 12:27:29 AM
Can that be generalised to a^n? Cos that method is really interesting.


Title: HELP: Why does this not work?
Post by: na_th_an on August 11, 2003, 05:45:42 AM
Nope. That method woks 'cause of the binary nature of the AND operator.


Title: HELP: Why does this not work?
Post by: oracle on August 11, 2003, 07:47:42 PM
Awww... (ambitious StatLib plans down drain) :lol: