guest (141.136.245.182)
Feb 23, 2013
=Numbers in Liberty BASIC= (all you ever wanted to know about numbers but did not know whom to ask ;) ) //by [[user:tsh73]]//, January 2012 [[toc]] ---- Liberty BASIC has only two data types: string and numbers. So if you have any numerical result it entitled to be "just a number". However, "under the hood" numbers in any programming language are a bit more complicated. Liberty BASIC is not an exception – and has complications (and unique abilities) of its own. To get most out of Liberty BASIC, you must understand what’s going on. Numbers could be integers (AKA whole numbers) – without decimal point – and real numbers (AKA floating point numbers). Since Liberty BASIC has no Boolean (logical, yes/no true/false) datatype, numbers are used for this purpose as well. =Integer numbers= Whole numbers like 0, 1, 123, -7 are integers. Combining integers with + - * MOD operators produces a result that is also an integer. Obviously, result of a division could end up as a non-integer (having fractional part). It is less obvious that power operators on integers could produce non-integer results: for example, 2^(-1) is actually 0.5. Liberty BASIC has no "integer division" operator, but it could be done as INT(a/b), taking only the integer part of result. ==Long integers (aka Arbitrary length integers)==Now,Now, there is a somewhat **unique strong point** in Liberty BASIC: in most of languages, the size of an integer is determined by the underlying computer architecture.QBasic's integer type is stored in 2 bytes, and hence limited to +/- 2^15, from -32,768 to 32,767. In contemporary C, an integer is stored in 4 bytes, so it is limited to +/-2^31, from -2,147,483,648 to 2,147,483,647. To get all 158 digits of 100! (factorial of 100, defined as 1*2*3*...*99*100) in these languages one has to invent things, but for Liberty BASIC, numbers of such length pose no problem: [[code format="lb"]] f=1 n=100 for i=1 to nf=f*if=f*i next print len(str$(f)) print f [[code]] output is (line breaks added to the long number for page formatting): [[code]] 158 – number of digits and factorial itself, hold your breath: 9332621544394415268169923885626670049071596826438162146859296389 5217599993229915608941463976156518286253697920827223758251185210 916864000000000000000000000000 [[code]] It looks like the length of those integers is limited only by available memory and computer speed (of course working with these beasts will be slower!). So getting 10^10000 might take several seconds. But it works, and with all digits! Functions VAL( ) and STR$( ) in Liberty BASIC support long integers.(Of course) +, -, *, as well as ^ and MOD supports long integers. > If a is a long integer and a/b is supposed to be whole number, >> then a/b will be a long integer>>>> else a/b willbebe a real number (and it even could overflow). There are some beneficial quirks about INT(a/b):> If a is a long integer, and a/b is supposed to be real number, >> then result will be a long integer (with all digits preserved). Also we evade real overflow. It looks like Liberty BASIC somehow bypasses the intermediate step of storing a/b as real. It looks like when calling standard math functions, the argument is converted to the "real" data type. This way, you can get overflow. So while 10^200 is within double range, you cannot get it by sqr(10^400) – 10^400 will try to convert to real and overflow.=Real numbers= Storing (small) integers is rather straightforward but our data or result turns out to be non-integer. It strongly looks like they end up stored in common in some other languages DOUBLE data type. This data type came with common limitations (existing in many programming languages): ==Range limitation== Here is data on limitation for double-precision numbers from QBasic Help: >Positive 1.79769313486231D+308 4.940656458412465D-324Positive 1.79769313486231D+308 4.940656458412465D-324 >Negative -4.940656458412465D-324 -1.79769313486231D+308Negative -4.940656458412465D-324 -1.79769313486231D+308 If your result exceeds these limits, you’ll get overflow error. In Liberty BASIC, it is easy to get when working with long integers. ==Precision limitation== Double real value stores only about 16 "real" digits. You can check it with USING function:[[code format="lb"]] mask$="#."forfor i=1 to 20: mask$=mask$+"#": next'20'20 digits after "." print using(mask$, 1/3) print "*.12345678901234567890" [[code]] prints [[code]] 0.33333333333333331968 *.12345678901234567890 [[code]] , that is, we get “garbage” after 16-th digit. Just checking how small number d should be so 1+d will register as d: [[code format="lb"]] d=1 for i=1 to 20d=d/10 a=1+d printd=d/10 a=1+d print i,1-a next [[code]] ==Precision limitation consequences== This gives some really bad things you should be aware of (and it is not a bug, it is a way real numbers work in pretty much any language): * **You should not count on real numbers being exact.** * **You should never test real numbers for being exactly equal.** [[code format="lb"]] a = 2.1 - 2 b = 0.1 print a, b if a=b then print "Equal" else print "Not equal" print "Difference "; a-b [[code]] Output: [[code]] 0.10.10.1 Not equal Difference 0.83266727e-16 [[code]] Instead, you should test for equality with given precision: [[code format="lb"]] precision = 1e-10ifif abs(a - b) < precisionthenthen print "Equal with precision" else print "Not equal" [[code]] * **You should not make FOR loops with realstep, > ifstep,** > **if the number of steps is important** (like in numerical integration).[[code format="lb"]] for i = 1 to 2 step 0.1ifif n = 0 then usingS$="0e+0":exit functionfmt$fmt$ = "#"+left$(".",prec>0)+left$("#################",prec)'fmt of mantissas$=left$("-",n<0) n=abs(n) log10=log(n)/log(10) e=int(log10)-(log10<0) 'QBs$=left$("-",n<0) n=abs(n) log10=log(n)/log(10) e=int(log10)-(log10<0) 'QB like INT. Makes mantissa for negative exponents'start'start from digit (not 0 as LB do)p=10^e ifp=10^e if left$(using(fmt$,n/p),1)="%" then p=p*10:e = e+1usingS$=s$+using(fmt$,n/p)usingS$=s$+using(fmt$,n/p) +"e"+left$("+",e>0) +str$(e)'Excel always shows "+" for exponent end function [[code]] =Using numbers as Booleans= As was stated, Liberty BASIC lacks a Boolean type, but it does have conditional statements. A condition normally evaluates to false or true. If we print result of any relational operator (> < = >= <= <>), we'll see that true prints as 1 and false prints as 0. This explains construction like eternal loop: [[code format="lb"]] While 1...... Wend [[code]] Also it opens possibilities for using a condition result as a number in some shortcuts like this one: [[code format="lb"]] y=x*(x>0) [[code]] (returns x if it is >0, otherwise 0)The only official rule is "**0 represents false, everything else means true**". That allows for things like [[code format="lb"]] If instr(txt$,searchFor$) then [[code]] Meaning the same as [[code format="lb"]] If instr(txt$,searchFor$)<>0 then [[code]] That is, "if searchFor$ is found in txt$".However when working with Boolean expressions involving numbers other then 0 and 1, one should take into account that logical operators AND OR XOR are bitwise: [[code]] 5 or 3 -> 7 (101 or 011 -> 111) 5 and 3 -> 1 (101 and 011 -> 001) 5 xor 3 -> 6 (101 xor 011 -> 110) [[code]] You can examine bits in a number with functionBitPattern$:BitPattern$: [[code format="lb"]]functionfunction BitPattern$(num)forfor i = 0 to 31ifif i mod 8 = 0 then BitPattern$ = " " + BitPattern$BitPattern$BitPattern$ = str$((num and 2 ^ i) > 0) + BitPattern$nextnext i end function [[code]] So it is possible to get [[code format="lb"]] a=1:b=2 if a then print "a is true" else print "a is false" if b then print "b is true" else print "b is false" if a and b then print "a and b is true" else print "a and b is false" [[code]] resulting at [[code]] a is true b is true a and b is false [[code]] Also note that some functions returns -1 for true. One such function is (EOF(#handle))Function NOT(x), contrary to logical operators, is not bitwise. It returns -1 for true, too. You can get bitwise NOT(x) as (x XOR -1) (it looks like -1 in binary representation has 32 bits set).There are **two exceptions** to the rule "0 represents false, everything else means true": 1) Syntax of SELECT CASE allows conditions in CASE, but here only the value 1 is accepted as true; others (including -1) are considered false. [[code format="lb"]] x = 1 select case case x: print "true" case else: print "false" end select'prints'prints true x = -1 select case case x: print "true" case else: print "false" end select'prints'prints false [[code]] 2) while real number like 0.1 is surely not 0, you cannot use reals instead of conditions. BASIC just dies at runtime with "isEmpty not understood" error. [[code format="lb"]] x = .1ifif x then print "true" else print"false" '"false" ' dies at runtime with "isEmpty not understood" error. [[code]] ---- [[toc]]