0

Currently I am facing a problem where when I multiply two numbers
5e20 * 5e20 = 2.5E41
it overflows from 128 bit max range that can only contain a maximum number with 39 digits. So I cannot multiply two very big numbers due to which my precision is reduced. I want precision up to 16 decimal places. If I perform division of numbers as well
10 / 3 = 3.3333333
I get only 3 because my system doesn't contain floating point so floating part is ignored. In order to achieve the precision, I scale up my dividend by multiplying it 1e16 to get 16 decimal precision. I also tried to use scientific notation to solve my precision so that I can multiply and divide
2.5/4 or 2.5x4
by writing
25x10^-1 and 4x10^0 but due to this, my multiplication remains in scale-down format while my division remains in scaled-up form
2.5/4 = 6.25E16 * 10^-1 (scaled up)
2.5*4 = 100 * 10^-1 (scaled down)

How can I solve this problem? What approach should I use?

Saad Tahir
  • 325
  • 2
  • 13
  • 3
    Your system don't contain floating-point? In which platform are you working on? Did you try mini-gmp in [GMP](https://gmplib.org/) library? Please provide more information so we can reproduce the exact problem, with a [minimal, repreducible example](https://stackoverflow.com/help/minimal-reproducible-example). – Arc Jan 12 '22 at 07:16
  • I am working on Smart Contract language called Clarity by Stacks Blockchain. It is very minimal and doesn't have structs, OOP, loops etc. All I can do is store in tuples. – Saad Tahir Jan 12 '22 at 10:14
  • @Déjàvu I am using tuples to store mantissa and exponent but the problem starts in my division precision. Like I said in the question, I can't do 10/3 and get 3.3333 unless I multiply divided 10 by 1e16 – Saad Tahir Jan 12 '22 at 10:19
  • When you write “I can't do 10/3 and get 3.3333 unless I multiply divided 10 by 1e16,” that says “I have a solution, it is to multiply divided 10 by 1e16” (although your phrasing there seems a bit off). That says you have a solution, so it is not clear what your problem is. You should clarify the problem and be specific. You want to divide 10 by 3 with 16 digits of precision. So you multiply 10 by 1e16 then divide by 3, giving 33,333,333,333,333,333. So the result is 33,333,333,333,333,333 scaled by 1e-16, or 33,333,333,333,333,333e-16. Now you have the result. What is the problem? – Eric Postpischil Jan 12 '22 at 12:59
  • Is it that result is useless to you because you do not know how to do further arithmetic between it and other numbers? If so, what do you want to do with it? – Eric Postpischil Jan 12 '22 at 12:59
  • I want to achieve Power of two numbers that can be negative, floating etc. I have got the solution for mul and div in scientific notation but I don't know how to write pow function using the scientific notation. @EricPostpischil – Saad Tahir Jan 13 '22 at 07:03
  • @SaadTahir: If you want to write a routine that can raise numbers to integer powers, it can be done reasonably by repeated squaring and multiplication. If you want to write a routine that can raise numbers to arbitrary powers of non-integer numbers, you need to work on a number of precursor routines, including logarithms and exponentiation with a fixed base. This cannot be addressed in a comment; you should look to other Stack Overflow questions and other resources for that. – Eric Postpischil Jan 13 '22 at 13:40

2 Answers2

1

There is no easy answer, you'll have to either implement operations for 256 bits integers (still not going to help your division, where you should use a scaling factor to represent your numbers), implement operations for a fixed point representation, or operations for a floating point representation (mantissa + exponent), none of which are trivial endeavors.

For a 256 bits arithmetic, someone had created a proof of concept (but not battle tested): https://github.com/KStasi/clarity-uint256-lib. She was using 4 uint64 to be able to use uint128 arithmetic without overflows.
Here's a 16 bits multiplication using an 8 bit multiplier:https://www.techiedelight.com/multiply-16-bit-integers-using-8-bit-multiplier/. You'll need to do similar things with 128 bit numbers.

Similarly, here are some pointers for doing a division with lower precision arithmetic: http://www.mattmillman.com/mcs-48-the-quest-for-16-bit-division-on-the-8-bit-cpu-which-cant-divide-anything/

Instead of using a scaling factor, an other approach would be to use fixed point representation. See https://en.wikipedia.org/wiki/Fixed-point_arithmetic for theory, and https://schaumont.dyn.wpi.edu/ece4703b20/lecture6.html for more practical considerations (some DSPs have the same issue, they only have integer operations).

Pascal Belloncle
  • 11,184
  • 3
  • 56
  • 56
  • I've seen this repo by KStasi but it doesn't work for me to write Power and Log functions from it. As it gets really hard to solve this. Any idea how can I create power and log functions in Clarity? Using scientific notation maybe? – Saad Tahir Jan 13 '22 at 09:21
  • for power and log, most implementations I'm aware of require an unknown number of iterations till it converges enough. For log, you may be able to use tables, and do some interpolation between the data points. Some pointers on some of the math required from https://medium.com/coinmonks/math-in-solidity-part-5-exponent-and-logarithm-9aef8515136e, but you still have the challenge of unknown number of iterations, which is not possible in clarity your best bet would be to request more native functions like `pow` to help implementing the full functions – Pascal Belloncle Jan 14 '22 at 03:11
0

The problem here is that the scientific notations are not the same for both the operations. For example,
2.5/4 = 6.25E16 * 10^-1 (scaled up)
2.5*4 = 100 * 10^-1 (scaled down)
Here you can simply just add -16 to the exponent part if you are multiplying 1e16 in the mantissa. So your answer becomes 2.5/4 = 6.25E16 * 10^-1 (scaled up)
2.5/4 = 6.25E16 * 10^-1 * 10^-16
2.5/4 = 6.25E16 * 10^-17
2.5/4 = 0.625

With this, both your multiplication and division are in scientific notations and result in the actual numbers.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Saad Tahir
  • 325
  • 2
  • 13