LoginLogin

Arbitrary Precision Calculator w/ Library

Root / Submissions / [.]

amihartCreated:
Download:J3A3EEK6
Version:0.7Size:
This is an arbitrary precision calculator, essentially meaning it always gives exact numbers. It only supports positive integers. The program APCALC supports order of operations, as shown in the screenshot. This program comes with both APCALC and APCALC.LIB. APCALC is an actual calculator that supports order of operations. The .LIB is a library you can import into your code and then do math using arbitrary precision. The calculator supports these operators:
  • + (addition)
  • - (subtraction)
  • * (multiplication)
  • / (division)
  • % (modulus)
  • ^ (exponentiation)
  • & (bitwise AND)
  • | (bitwise OR)
  • ! (bitwise XOR)
  • < (left shift)
  • > (right shift)
Converting between decimal strings and APCALC variables is rather slow so some operations in the actual calculator can seem like they're taking forever but they're actually really quick, it's just atm the conversion is really slow, so like even though addition is really fast, 1000000000000...000000+1 might be slow because it has to convert that decimal string to an APCALC variable, do the math, then back again to show you the results. I will hopefully figure out a way to speed up this conversion process in the future. Update 1: - Slightly better performance. - Automatic removal of trailing zeros. - New added "_SAVE" and "_LOAD" function which compresses your files into 32-bit integer arrays. - Added "_GCD" function to find the greatest common divisor between two numbers (Euclid's algorithm). - Added "_RND" function for generating a random APCALC variable.

Instructions:

Run APCALC to use the calculator. Open DEV_EXAMPLE if you want to see how to use the library.

But as long as you pre-create the APCALC variables and only use those variables in all future math, it's fast right?

Replying to:haloopdy
But as long as you pre-create the APCALC variables and only use those variables in all future math, it's fast right?
It's pretty fast for most operations, yeah. The APCALC variables are stored in strings, and if you have a string of just 10 characters long, you can hold any number between 0 and 1,461,501,637,330,902,918,203,684,832,716,283,019,655,932,542,976. And obviously it doesn't take very long to operate on only 10 characters. The larger the number, the longer the string, and the slower it'll take to operate on it, but you can get to pretty massive numbers without noticing any slowdown.

Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
Why does code in comments wrap.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
because your screen is too small

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
Thanks. I'll implement this and upload a new version later today.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
You also might want to create OUT$ with the correct size to begin with, if this is known (for example, with bitwise OR)
COMMON DEF _OR(A$,B$)
 VAR L%=MAX(LEN(A$),LEN(B$))
 VAR OUT$=" "*L%
 VAR I%
 FOR I%=0 TO L%-1
  OUT$[I%]=CHR$(ASC(A$[I%]) OR ASC(B$[I%]))
 NEXT
 RETURN OUT$
END
This is faster because you don't need too resize the strings, but it will not remove extra CHR$(0)s , so you'll either have to do that separately, or only use this method in operations where the output length is known.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
Alright. The _CMP statement didn't seem to work, it seems to think "000" > "0" which obviously isn't true, and if I were to build in a check for this it might slow it down even further, I'd still need to iterate through the whole thing to remove excess 0s.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
I don't think any of your functions add leading 0s, though it's probably a good idea to check for them in your compare function unless you're completely sure.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
Functions the produce a smaller number can have leading zeros. e.g. in base-65536 the number 65536 is [1][0] so if I do 65536-1 I get [0][65535].

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
You should probably make it not add leading 0s, to avoid memory leaks. Once a number has leading zeros they probably won't go away.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
I can add a method to allow the user to optionally trim down numbers to remove trailing zeros. I don't want to force it to trim the number every time because of unnecessary slowdown. The memory space essentially expands to the max size of what is needed to do your operations.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
nvm I'll just add a trim method and include it at the end of the methods that might leave trailing zeros. Hopefully it won't effect performance too much.

Replying to:12Me21
Your _CMP function can be replaced with
COMMON DEF _CMP(A$,B$)
 IF A$>B$ THEN RETURN 1
 IF A$<B$ THEN RETURN -1
 RETURN 0
END
(And you can just compare strings directly most of the time; for example _CMP$(T$,CHR$(0))!=0 can be T$!=CHR$(0)) You can also replace:
STRING$=STRING$+... -> PUSH STRING$,...
STRING$=...+STRING$ -> UNSHIFT STRING$,...
MID$(STRING$,POSITION,1) -> STRING$[POSITION]
Loading the library can be done with
USE "PRG1:APCALC.LIB"
If you really want it to be as fast as possible you could use arrays instead, but it wouldn't be as convenient since you'd always have to DIM them .

Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?

Replying to:Simeon
Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?
It depends on how long the number you're operating on and whether or not you're using the new or old 3DS as well as the specific operation you're doing. Here's a graph of the multiplication function. The X axis is number of 9s being multiplied. Such that 5 on the X axis is 99999*99999. The Y axis is the number of milliseconds it takes to execute. As you can see, it gets slower the larger the number gets. It hits 100 milliseconds at about 55, so if you multiply
9999999999999999999999999999999999999999999999999999999*9999999999999999999999999999999999999999999999999999999
it will take about 100 milliseconds to calculate on the new 3DS. I haven't done anything on the old 3DS but I tend to find that the difference in speed is about 3.4, meaning it would likely take about 340 milliseconds on the old to calculate that. It's obviously not completely linear as well. I did multiplication because it's sort of in the middle, it's slower than addition but faster than division, and I did all 9s because that produces the largest result, so your result is a lot larger than the two numbers being multiplied. On the new 3DS, it takes about 3.5 seconds to evaluate this statement:
9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999*9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
(this is one-thousand 9s multiplied by another one-thousand 9s) I'd guess 12 seconds on the original 3DS.

Replying to:Simeon
Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?
Oh wow! That is impressive I just ran the same test on mine 1000 nines multiplied by 1000 nines Takes 7.2 seconds Yours is almost twice as fast, which is impressive because I spent a long time making mine as efficient as possible

Replying to:Simeon
Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?
On the original 3DS or the new 3DS? If it's the original 3DS it's actually a little faster. And how did you do yours? I did mine using strings and treating them as base-65536 numbers.

Replying to:Simeon
Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?
No mine is on a New 3DS too, so yours is faster How I did mine, treated each number as a base-10 number string, I do have overhead on mine because I put a lot of focus on positive and negatives. I then used my library to recreate java.util.random. Successfully made java's pseudo random work on SmileBASIC, so that I could create a slime chunck finder (Minecraft) After the slime chunk finder was done, it was extremely laggy java.util.random took roughly 120 milliseconds per number So this project came to an immediate end There must be a way to do this without strings I couldn't figure it out

Replying to:Simeon
Brilliant! I created this too a while back, but mine was too slow Could you give us some insight on the benchmarks; how many milliseconds each operation takes?
Ah, base-10 number strings are going to be slower because you have to iterate through more characters. If I wanted to do something with the number 150000000000000000000000000000000000000000000000, in your library you'd have to iterate through all 49 characters while my library would only have to iterate through 10 characters. And yours also seems to work with negative numbers which may also be a reason, as you mentioned. The reason mine is positive integer only is really because I just built it so I could play around with RSA encryption, which this is sufficient for it.