Creating a system for arbitrarily large numbers to surpass 1.6e+308 limit

So I have been wanting to create a system where I can create arbitrarily large numbers exceeding the number limit (about 1.6e+308) with two variables: a base and an exponent.

The base would act as a number from (0, 10), or in other words, a number that is anywhere between 0 to 10. The exponent would act as the exponent, of course. This system could theoretically produce numbers as large as 1 + 1e+308 which is stupendously large and more than anyone would ever need.

Example:

local base = 3.25
-- base is a number that is between 0 and 10
local exponent = 36

-- 3.25e+36

base = 9.6
exponent = 3e+16

-- 9.6e+32000000000000000
-- HUGE NUMBER, most likely won't go this high

Now, this is easy enough: just adjust exponent accordingly dependent on base.
The problem occurs when I attempt to make a function for adding these numbers:

local function Add(n1, n2)
-- string inputs
-- string.split function goes here to separate base and exponent
-- code that does stuff, this is the part I don't know
end

Add(2.5e+47, 3e+48) -- identical to 2.5e+47 + 3e+48
-- returns 3.25e+48

Is this a practical method of making a number system, or should I just use a library that handles it for me? I tried using BigNum, but the most it can handle for my tastes is somewhere around 1e+1200, which is large, but not large enough :stuck_out_tongue:

If this is practical, how would I go about creating the necessary functions such as multiplication, division, and exponentiation? It is confusing me a lot, haha. Any pointers would be appreciated, I don’t expect my code to be written for me.

EDIT: Additionally, would it be a smart idea to use string functions to separate the +e from the numbers, i.e., 6e+56 = 6 and 56. This isn’t necessary, but it would make things simpler.

3 Likes

I’ve added some more information regarding the post and I’ve looked through the documentation of BigNum. I experimented with increasing the radix value to 256, but that caused the script to kill itself due to a lack of response. 128 got the 1e+1200 limit as I stated in the OP, but I was wondering if BigNum could be used as a way of augmenting this system I have come up with?

Thanks for viewing :slight_smile:

2 Likes

I didn’t consider accuracy. I don’t want to use conventional numbers; I just want to be able to represent large quantities. I would assume the base would keep accuracy; for example, you could have 5.2486e+3947488 as a number. It’s stupidly big and can’t be converted to standard notation in any way, shape, or form, but you can definitely convert it into a prefix using some fancy math.

Also I didn’t consider binary haha :stuck_out_tongue:
I was just thinking of checking if the base was >=10 or <=0, in which case I’d add/subtract one to exponent. Same with mult/division, powers, etc.

1 Like

Sorry to be a little late to the party.

What you could do is represent each number as a table containing a decimal number and an integer representing a power of 10 to multiply the decimal by, similar to scientific notation, which, if you aren’t familiar with, I’d suggest at least skimming through the article, as I’m going to use some of the terminology related to it in my suggestion.

For example, 1,500,000 would be represented as {1.5, 6} and 50,000 would be represented as {5, 4}.

Multiplication and division would be the easiest mathematical operations to apply to this system.

Multiplication could be done by simply multiplying the coefficients in each table, i.e., 1.5 * 5 = 7.5, then adding the exponents in each table together, i.e., 6 + 4 = 10, to get the new power of 10 to multiply the new coefficient by.

This would give you a new table {7.5, 10}, representing 7.5 X 1010 or 75,000,000,000, the same number you would get if you multiply 1,500,000 by 50,000.

Division would be a similar process, just reversed.

To divide {1.5, 6} by {5, 4}, you would do 1.5 / 5 to get 0.3. You would then subtract the powers to get the new power of 10 for the quotient, i.e., 6 - 4 = 2.

This would give you a new table {0.3, 2}, representing 0.3 X 102 or 30, the same number you would get if you divide 1,500,000 by 50,000.

Of course, if you keep dividing the same number over and over again, you’re going to end up with a ton of zeros following the decimal point in the coefficient. A good way to solve this would be to test if the new coefficient is less than zero. If it is, multiply the coefficient by 10, and subtract 1 from the exponent. In this case, {0.3, 2} would now become {3, 1}, both representing 30.

The same method could be applied to multiplication to ensure you don’t end up with a coefficient with a ton of numbers proceeding the decimal point. Simply test if the new coefficient is greater than or equal to 10, and if it is, divide it by 10 and add 1 to the exponent.

As an example, if you had {12.5, 4}, representing 125,000, you would divide the coefficient 12.5 by 10, and add 1 to exponent 4, giving you {1.25, 5}, which also represents 125,000.

I’m not 100% sure of the exact details of implementing addition and subtraction, and I don’t want to give you the wrong process, but I’d assume a good way to do it would be to test for the difference in exponents between the two numbers and to perform the addition or subtraction that many places away from the decimal point, then use that answer as the new coefficient and determine if any adjustment needs to be made to the exponent.

Using this method, instead of having a maximum number value of 1.6 X 10308, you can now have 1.6 X 10308 digits in each number.

EDIT: oops the computer science student forgot some zeros in a number :slight_smile:

4 Likes

Also just a side note, out of curiosity I went and calculated it and apparently 1.7976931348623 X 10308 is the theoretical maximum value of a number you can have before Roblox represents it as math.huge or infinity.

2 Likes

This seems to be a good way of handling it; however, my only concerning is comparing exponents that exceed a distance of* 308. Because we are still using numbers, I have a fear that attempting to compare {1, 3} and something like {1, 405} would result in an error due to the fact that attempting to balance either number to equal the exponent of the other would result in an error when moving the base by that many places in order to set it equal.

A part of me just wants to ignore any comparison that exceeds this limit, because obviously adding a number so small to a number so big is pointless due to the massive size comparison, but this could potentially cause issues. Is this a good way of handling this?

This wouldn’t be a problem with multiplication and division.

This is due to the fact that the coefficients are simply multiplied or divided and the exponents are just added or subtracted depending on whether the operation is multiplication or division, respectively.

Using your {1, 3} and {1, 405} example with multiplication, the operation would look like this.

New coefficient → 1 * 1 = 1
New exponent → 3 + 405 = 408
New number → {1, 408}

1 Like

The 1.79e308 number you found is (1-2^-53)*2^1024, which is the limit of double precision floating point numbers. Using a custom representation where you just store the precision part separately from the exponent part (which is how floating point numbers work already), you can define your own addition and multiplication operations on it.

Addition/subtraction should convert the number with the smaller exponent first, so 3.14e98 + 3.14e100 turns into .0314e100 + 3.14e100 = 3.1714e100. For multiplication, multiply the coefficient parts and add the exponent part, e.g. 3.14e98 * 3.14e100 = 9.8596e198.

Here's an example implementation
local big = {}
big.__index = big

function big.new(coefficient, exponent)
	return setmetatable({c = coefficient, e = exponent}, big)
end

function big.__tostring(self)
	return self.c.."e"..self.e
end

function big.__add(a, b)
	local e = math.max(a.e, b.e)
	local c = a.c*10^(a.e-e) + b.c*10^(b.e-e)
	if math.abs(c) >= 10 then
		c, e = c / 10, e + 1
	end
	return big.new(c, e)
end

function big.__mul(a, b)
	local e = a.e + b.e
	local c = a.c * b.c
	if math.abs(c) >= 10 then
		c, e = c / 10, e + 1
	end
	return big.new(c, e)
end

function big.__unm(self)
	return big.new(-self.c, self.e)
end

function big.__sub(a, b)
	return a + -b
end

function big.__div(a, b)
	local e = a.e - b.e
	local c = a.c / b.c
	if math.abs(c) < 1 then
		c, e = c * 10, e - 1
	end
	return big.new(c, e)
end
local a = big.new(3.14, 98)
local b = big.new(3.14, 100)
print(a + b, a - b, b - a)
print(a * b, a / b, b / a)
6 Likes