The Math Wizard's Library for BASIC page 1
MATHWIZ Copyright (c) 1991 Thomas G. Hanlin III
This is MATHWIZ, a library of assembly language and BASIC routines for use
with QuickBASIC version 4.5. Support for other recent versions of the BASIC
compiler is provided with registration. The MATHWIZ collection is
copyrighted and may be distributed only under the following conditions:
1) No fee of over $10.00 may be charged for distribution. This
restriction applies only to physical copies and is not meant to
prevent distribution by telecommunication services.
2) All MATHWIZ files must be distributed together in original, unaltered
form. This includes MATHWIZ.BI, MATHWIZ.DOC, MATHWIZ.LIB, MATHWIZ.NEW,
MATHWIZ.QLB, MATHWIZ.REF, BIBLIO.TXT, CATALOG.TXT, FILES.LST,
LIBRARY.TXT, QUESTION.TXT, and REGISTER.TXT.
You use this library at your own risk. It has been tested by me on my own
computer, but I will not assume any responsibility for any problems which
MATHWIZ may cause you. If you do encounter a problem, please let me know
about it, and I will do my best to verify and repair the error.
It is expected that if you find MATHWIZ useful, you will register your copy.
You may not use MATHWIZ routines in programs intended for sale unless you
have registered. Registration entitles you to receive the latest version of
MATHWIZ, complete with full source code in assembly language and BASIC. The
assembly code is designed for the OPTASM assembler by SLR Systems and will
require modifications if you wish to use it with MASM or TASM. You will be
able to compile the BASIC code with whatever version of the compiler you
have, allowing you to use MATHWIZ with QuickBASIC versions 4.0 - 4.5 and
BASCOM versions 6.0 - 7.1 (QBX and BASCOM 7.x far strings aren't supported).
Warning: Use of MATHWIZ for more than 30 days without registering has been
determined to cause the Surgeon General to issue warning labels! If you use
this product, please do register.
For an example of how to set up your program to access the MATHWIZ library,
how to LINK the routines, and so forth, see the LIBRARY.TXT file.
So who's the Math Wizard? With this library, you will be! Read this
tome well, for invoking these routines without proper preparation may bring
unexpected results. Cape and hat (optional) not included. No assembly
Note that MATHWIZ may be considered an extension of my main BASIC library,
BASWIZ. See CATALOG.TXT for additional information.
Table of Contents page 2
Overview and Legal Info ................................................ 1
Extensions to BASIC's floating point ................................... 3
BCD Math ............................................................... 4
Fractions .............................................................. 7
Miscellaneous Notes .................................................... 8
Troubleshooting ........................................................ 9
Using MATHWIZ with PDQ ................................................ 10
Extensions to BASIC's floating point page 3
For the most part, this library is designed to provide alternatives to the
math routines that are built into BASIC. Still, BASIC's floating point is
quite adequate for many purposes, so there's no sense in ignoring it. Here
are a few functions which make BASIC math a bit more convenient.
Result! = FactS!(Nr%) ' factorial
Result! = CotS!(Nr!) ' cotangent
Result! = CscS!(Nr!) ' cosecant
Result! = SecS!(Nr!) ' secant
Result! = Deg2RadS!(Nr!) ' convert degrees to radians
Result! = Rad2DegS!(Nr!) ' convert radians to degrees
Result! = Cent2Fahr!(Nr!) ' convert centigrade to Fahrenheit
Result! = Fahr2Cent!(Nr!) ' convert Fahrenheit to centigrade
Result! = Kg2Pound!(Nr!) ' convert kilograms to pounds
Result! = Pound2Kg!(Nr!) ' convert pounds to kilograms
Pi! = PiS! ' the constant "pi"
e! = eS! ' the constant "e"
Result# = FactD#(Nr%) ' factorial
Result# = CotD#(Nr#) ' cotangent
Result# = CscD#(Nr#) ' cosecant
Result# = SecD#(Nr#) ' secant
Result# = Deg2RadD#(Nr#) ' convert degrees to radians
Result# = Rad2DegD#(Nr#) ' convert radians to degrees
Pi# = PiD# ' the constant "pi"
e# = eD# ' the constant "e"
Like BASIC, the trig functions expect the angle to be in radians. Constants
are expressed to the maximum precision available. If you are not familiar
with variable postfix symbols, "!" indicates single precision and "#"
indicates double precision. See your BASIC manual for further details.
BCD Math page 4
Some of you may not have heard of BCD math, or at least not have more than a
passing acquaintance with the subject. BCD (short for Binary-Coded Decimal)
is a way of encoding numbers. It differs from the normal method of handling
numbers in several respects. On the down side, BCD math is much slower than
normal math and the numbers take up more memory. However, the benefits may
far outweigh these disadvantages, depending on your application: BCD math is
absolutely precise within your desired specifications, and you can make a BCD
number as large as you need. If your applications don't require great range
or precision out of numbers, normal BASIC math is probably the best choice.
For scientific applications, accounting, engineering and other demanding
tasks, though, BCD may be just the thing you need.
The BCD math routines provided by MATHWIZ allow numbers of up to 255 digits
long (the sign counts as a digit, but the decimal point doesn't). You may
set the decimal point to any position you like, as long as there is at least
one digit position to the left of the decimal.
Since QuickBASIC doesn't support BCD numbers directly, we store the BCD
numbers in strings. The results are not in text format and won't mean much
if displayed. A conversion routine allows you to change a BCD number to a
text string in any of a variety of formats. The BCD numbers can also be
compressed to allow more efficient storage.
Note that the BCD math handler doesn't yet track overflow/underflow error
conditions. If you anticipate that this may be a problem, it would be a good
idea to screen your input or to make the BCD range large enough to avoid
Let's start off by examining the routine which allows you to set the BCD
BCDSetSize LeftDigits%, RightDigits%
The parameters specify the maximum number of digits to the left and to the
right of the decimal point. There must be at least one digit on the left,
and the total number of digits must be less than 255. The BCD strings will
have a length that's one larger than the total number of digits, to account
for the sign of the number. The decimal point is implicit and doesn't take
up any extra space.
It is assumed that you will only use one size of BCD number in your program--
there are no provisions for handling mixed-length BCD numbers. Of course,
you could manage that yourself with a little extra work, if it seems like a
useful capability. If you don't use BCDSetSize, the default size of the BCD
numbers will be 32 (20 to the left, 11 to the right, 1 for the sign).
You can get the current size settings in your program, too:
BCDGetSize LeftDigits%, RightDigits%
BCD Math page 5
Before doing any BCD calculations, you must have some BCD numbers! The
BCDSet routine takes a number in text string form and converts it to BCD:
TextSt$ = "1234567890.50"
Nr$ = BCDSet$(TextSt$)
If your numbers are stored as actual numbers, you can convert them to a text
string with BASIC's STR$ function, then to BCD. Leading spaces are ignored:
Nr$ = BCDSet$(STR$(AnyNum#))
BCD numbers can also be converted back to text strings, of course. You may
specify how many digits to the right of the decimal to keep (the number will
be truncated, not rounded). If the RightDigits% is positive, trailing zeros
will be kept; if negative, trailing zeros will be removed. There are also
various formatting options which may be used. Here's how it works:
TextSt$ = BCDFormat$(Nr$, HowToFormat%, RightDigits%)
The HowToFormat% value may be any combination of the following (just add the
numbers of the desired formats together):
0 plain number
1 use commas to separate thousands, etc
2 start number with a dollar sign
4 put the sign on the right side instead of the left side
8 use a plus sign instead of a space if number is not negative
The BCD math functions are pretty much self-explanatory, so I'll keep the
descriptions brief. Here are the single-parameter functions:
Result$ = BCDAbs$(Nr$) ' take the absolute value of a number
Result$ = BCDCos$(Nr$) ' cosine function
Result$ = BCDCot$(Nr$) ' cotangent function
Result$ = BCDCsc$(Nr$) ' cosecant function
Result$ = BCDDeg2Rad$(Nr$) ' convert degrees to radians
e$ = BCDe$ ' get the value of the constant "e"
Result$ = BCDFact$(N%) ' calculate the factorial of integer N
Result$ = BCDNeg$(Nr$) ' negate a number
pi$ = BCDpi$ ' get the value of the constant "pi"
Result$ = BCDRad2Deg$(Nr$) ' convert radians to degrees
Result$ = BCDSec$(Nr$) ' secant function
Result% = BCDSgn%(Nr$) ' signum function
Result$ = BCDSin$(Nr$) ' sine function
Result$ = BCDSqr$(Nr$) ' get the square root of a number
Result$ = BCDTan$(Nr$) ' tangent function
BCD Math page 6
Notes on the single-parameter functions:
The signum function returns an integer based on the sign of the BCD number:
-1 the BCD number is negative
0 the BCD number is zero
1 the BCD number is positive
BCDpi is currently accurate to as many as 200 decimal positions. BCDe is
accurate to as many as 115 decimal places. The actual accuracy, of course,
depends on the size of BCD numbers you've chosen.
The trigonometric functions (cos, sin, tan, sec, csc, cot) expect angles in
radians. BCDDeg2Rad and BCDRad2Deg will allow you to convert back and
forth between radians and degrees, although some accuracy may be lost
inasmuch as they rely on BCDpi.
Here is a list of the two-parameter functions:
Result$ = BCDAdd$(Nr1$, Nr2$) ' add two numbers together
Result$ = BCDSub$(Nr1$, Nr2$) ' subtract the second nr from the first
Result$ = BCDMul$(Nr1$, Nr2$) ' multiply one number by another
Result$ = BCDDiv$(Nr1$, Nr2$) ' divide the first number by the second
Result$ = BCDPower$(Nr$, Power%) ' raise a number to a power
Result% = BCDCompare%(Nr1$, Nr2$) ' compare two numbers
The comparison function returns an integer which reflects how the two numbers
compare to eachother:
-1 Nr1 < Nr2
0 Nr1 = Nr2
1 Nr1 > Nr2
Fractions page 7
Using BCD allows you to represent numbers with excellent precision, but at a
fairly large cost in speed. Another way to represent numbers with good
precision is to use fractions. Fractions can represent numbers far more
accurately than BCD, but can be handled much more quickly. There are some
limitations, of course, but by now you've guessed that's always true!
Each fraction is represented by MATHWIZ as a string of 8 characters. The
numerator (top part of the fraction) may be anywhere from -999,999,999 to
999,999,999. The denominator (the bottom part) may be from 0 to 999,999,999.
This allows handling a fairly wide range of numbers quite exactly.
Fractions can be converted to or from numeric text strings in any of three
formats: real number (e.g., "1.5"), plain fraction (e.g., "3/2"), or whole
number and fraction (e.g., "1 1/2"). Internally, the numbers are stored as a
plain fraction, reduced to the smallest fraction possible which means the
same thing (for instance, "5/10" will be reduced to "1/2").
To convert a numeric text string into a fraction, do this:
Nr$ = FracSet$(NumSt$)
To convert a fraction into a numeric text string, try this:
NumSt$ = FracFormat$(Nr$, HowToFormat%)
The formatting options are:
0 convert to plain fraction
1 convert to whole number and fraction
2 convert to decimal number
Here is a list of the other functions available:
Result$ = FracAbs$(Nr$) ' take the absolute value of a fraction
Result$ = FracAdd$(Nr1$, Nr2$) ' add two fractions
Result% = FracCompare%(Nr1$, Nr2$) ' compare two fractions
Result$ = FracDiv$(Nr1$, Nr2$) ' divide the first fraction by the second
Result$ = FracMul$(Nr1$, Nr2$) ' multiply two fractions
Result$ = FracNeg$(Nr$) ' negate a fraction
Result% = FracSgn%(Nr$) ' signum function for a fraction
Result$ = FracSub$(Nr1$, Nr2$) ' subtract the 2nd fraction from the 1st
Fractions are automatically reduced to allow the greatest possible range.
Note that little range-checking is done at this point, so you may wish to
screen any input to keep it reasonable.
Result FracSgn FracCompare
-1 negative # 1st < 2nd
0 # is zero 1st = 2nd
1 positive # 1st > 2nd
Miscellaneous Notes page 8
A certain lack of speed is inherent in BCD math, especially if you require
high precision. The division, root, and trig routines in particular are
quite slow. I'll attempt to improve this in the future, but the routines are
already fairly well optimized, so don't expect miracles. Precision costs!
The fraction routines are much faster, but they have a much smaller range.
I'll have to do some experimenting on that. It may prove practical to use a
subset of the BCD routines to provide an extended range for fractions without
an unreasonable loss in speed.
I am hoping to add Bessel functions, matrix math, logarithms and other
goodies in the future as I am able to obtain information on how to handle
these things. Your suggestions as to good reference books and other routines
that might be useful will be most welcome.
Troubleshooting page 9
QB says "subprogram not defined".
The definition file was not included. Your program must contain the line
REM $INCLUDE: 'MATHWIZ.BI'
before any executable code in your program. You should also start
QB /L MATHWIZ
so it knows to use the MATHWIZ library.
LINK says "unresolved external reference".
Did you specify MATHWIZ as the library when you used LINK? You should!
The MATHWIZ.LIB file must be in the current directory or along a path
specified by the LIB environment variable (like PATH, but for LIB files).
The BCDSIN$ function returns strange results.
Make sure you have left some room on the left side of the decimal as well
as the right! The sine calculations can involve fairly large numbers.
Using MATHWIZ with PDQ page 10
Unfortunately, most MATHWIZ routines are not compatible with Crescent
Software's PDQ library. Some of the routines require floating point math,
which is not supported by PDQ. Many of the routines require dynamic string
functions, which aren't supported by PDQ either. So it goes.
Crescent thoughtfully provided me with a free copy of PDQ in order that I
might resolve any incompatibilities between it and my BASIC libraries. In
this case, it didn't prove practical to do so.
If you are not familiar with PDQ, it is a replacement library for BASIC's own
runtime libraries. While not providing every capability of plain QuickBASIC,
it allows you to create substantially smaller EXE files for those programs
that qualify. Support is currently lacking for floating point (single/double
precision) numbers, music, and graphics, among other things. I understand
that these will be added to a future version of the library. Communications
support is available as an add-on package. PDQ also adds new capabilities
which are quite impressive, such as being able to write small TSRs in BASIC.
Check with Crescent for more recent details.