Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arbitrary precision decimal float opcodes #79

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 21 additions & 12 deletions dev/TEAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,15 @@ return stack matches the name of the input value.
| `json_ref r` | key B's value, of type R, from a [valid](jsonspec.md) utf-8 encoded json object A |

The following opcodes take byte-array values that are interpreted as
big-endian unsigned integers. For mathematical operators, the
decimals. For mathematical operators, the
returned values are the shortest byte-array that can represent the
returned value. For example, the zero value is the empty
byte-array. For comparison operators, the returned value is a uint64.

Decimals are interpreted as follows:
Given A: uint64, B: []byte, width: uint64, E: uint64 interpret B as a big-endian unsigned integer and multiply that with:
(-1)^A * 10^((-1)^E * width)

Input lengths are limited to a maximum length of 64 bytes,
representing a 512 bit unsigned integer. Output lengths are not
explicitly restricted, though only `b*` and `b+` can produce a larger
Expand All @@ -371,18 +375,23 @@ bytes on outputs.

| Opcode | Description |
| - | -- |
| `b+` | A plus B. A and B are interpreted as big-endian unsigned integers |
| `b-` | A minus B. A and B are interpreted as big-endian unsigned integers. Fail on underflow. |
| `b/` | A divided by B (truncated division). A and B are interpreted as big-endian unsigned integers. Fail if B is zero. |
| `b*` | A times B. A and B are interpreted as big-endian unsigned integers. |
| `b<` | 1 if A is less than B, else 0. A and B are interpreted as big-endian unsigned integers |
| `b>` | 1 if A is greater than B, else 0. A and B are interpreted as big-endian unsigned integers |
| `b<=` | 1 if A is less than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers |
| `b>=` | 1 if A is greater than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers |
| `b==` | 1 if A is equal to B, else 0. A and B are interpreted as big-endian unsigned integers |
| `b!=` | 0 if A is equal to B, else 1. A and B are interpreted as big-endian unsigned integers |
| `b+` | Addition of decimals. |
| `b-` | Subtraction of decimals. Fail on underflow. |
| `b/` | Division of decimals (truncated division). Fail if B is zero. |
| `b*` | Multilpication of decimals. |
| `b<` | Less than, 1 if true, else 0. |
| `b>` | Greater than, 1 if true, else 0. |
| `b<=` | Less than xor equal, 1 if true, else 0. |
| `b>=` | Greater than xor equal, 1 if true, else 0. |
| `b==` | Equal, 1 if true, else 0. |
| `b!=` | Not equal, 1 if true, else 0. |
| `b%` | A modulo B. A and B are interpreted as big-endian unsigned integers. Fail if B is zero. |
| `bsqrt` | The largest integer I such that I^2 <= A. A and I are interpreted as big-endian unsigned integers |
| `bsqrt` | The largest integer I such that I^2 <= A. A and I are interpreted as big-endian unsigned integers. |
| `bpow` | Decimal to the power of a decimal. |
| `bexp` | e to the power of a decimal. |
| `bln` | Natural logarithm of a decimal. |
| `blog2` | Logarithm base 2 of a decimal. |
| `blog10` | Logarithm base 10 of a decimal. |

These opcodes operate on the bits of byte-array values. The shorter
input array is interpreted as though left padded with zeros until it is the
Expand Down
146 changes: 106 additions & 40 deletions dev/TEAL_opcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -1219,79 +1219,109 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with
- **Cost**: 130
- Availability: v7

## b+
## b+ widthB widthD widthY

- Opcode: 0xa0
- Stack: ..., A: []byte, B: []byte &rarr; ..., []byte
- A plus B. A and B are interpreted as big-endian unsigned integers
- Stack: ..., A: uint64, B: []byte, C: uint64, D: []byte, E: uint64, F: uint64, G: uint64 &rarr; ..., X: uint64, Y: []byte
- Addition of decimals. B and D are interpreted as big-endian unsigned integers.
- **Cost**: 10
- Availability: v4
- Availability: v9

wB = (-1)^E * widthB ; wD = (-1)^F * widthD ; wY = (-1)^G * widthY
[(-1)^A * B * 10^wB] + [(-1)^C * D * 10^wD] = (-1)^X * Y * 10^wY. widthB, widthD and widthY are uint64. widthY decimal output precision is guaranteed.

## b-
## b- widthB widthD widthY

- Opcode: 0xa1
- Stack: ..., A: []byte, B: []byte &rarr; ..., []byte
- A minus B. A and B are interpreted as big-endian unsigned integers. Fail on underflow.
- Stack: ..., A: uint64, B: []byte, C: uint64, D: []byte, E: uint64, F: uint64, G: uint64 &rarr; ..., X: uint64, Y: []byte
- Subtraction of decimals. B and D are interpreted as big-endian unsigned integers. Fail on underflow.
- **Cost**: 10
- Availability: v4
- Availability: v9

## b/
wB = (-1)^E * widthB ; wD = (-1)^F * widthD ; wY = (-1)^G * widthY
[(-1)^A * B * 10^wB] - [(-1)^C * D * 10^wD] = (-1)^X * Y * 10^wY. widthB, widthD and widthY are uint64. widthY output precision is guaranteed.

## b/ widthB widthD widthY

- Opcode: 0xa2
- Stack: ..., A: []byte, B: []byte &rarr; ..., []byte
- A divided by B (truncated division). A and B are interpreted as big-endian unsigned integers. Fail if B is zero.
- Stack: ..., A: uint64, B: []byte, C: uint64, D: []byte, E: uint64, F: uint64, G: uint64 &rarr; ..., X: uint64, Y: []byte
- Division of decimals (truncated division). B and D are interpreted as big-endian unsigned integers. Fail if D is zero.
- **Cost**: 20
- Availability: v4
- Availability: v9

wB = (-1)^E * widthB ; wD = (-1)^F * widthD ; wY = (-1)^G * widthY
[(-1)^A * B * 10^wB] / [(-1)^C * D * 10^wD] = (-1)^X * Y * 10^wY. widthB, widthD and widthY are uint64. widthY output precision is guaranteed.

## b*
## b* widthB widthD widthY

- Opcode: 0xa3
- Stack: ..., A: []byte, B: []byte &rarr; ..., []byte
- A times B. A and B are interpreted as big-endian unsigned integers.
- Stack: ..., A: uint64, B: []byte, C: uint64, D: []byte, E: uint64, F: uint64, G: uint64 &rarr; ..., X: uint64, Y: []byte
- Multilpication of decimals. B and D are interpreted as big-endian unsigned integers.
- **Cost**: 20
- Availability: v4
- Availability: v9

## b<
wB = (-1)^E * widthB ; wD = (-1)^F * widthD ; wY = (-1)^G * widthY
[(-1)^A * B * 10^wB] * [(-1)^C * D * 10^wD] = (-1)^X * Y * 10^wY. widthB, widthD and widthY are uint64. widthY output precision is guaranteed.

## b< widthB widthD

- Opcode: 0xa4
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 1 if A is less than B, else 0. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Less than, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

## b>
wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB < (-1)^C * D * 10^wD. widthB and widthD are uint.

## b> widthB widthD

- Opcode: 0xa5
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 1 if A is greater than B, else 0. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Greater than, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

## b<=
wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB > (-1)^C * D * 10^wD. widthB and widthD are uint.

## b<= widthB widthD

- Opcode: 0xa6
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 1 if A is less than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Less than xor equal, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

## b>=
wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB <= (-1)^C * D * 10^wD. widthB and widthD are uint.

## b>= widthB widthD

- Opcode: 0xa7
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 1 if A is greater than or equal to B, else 0. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Greater than xor equal, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

## b==
wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB >= (-1)^C * D * 10^wD. widthB and widthD are uint.

## b== widthB widthD

- Opcode: 0xa8
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 1 if A is equal to B, else 0. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Equal, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

## b!=
wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB == (-1)^C * D * 10^wD. widthB and widthD are uint.

## b!= widthB widthD

- Opcode: 0xa9
- Stack: ..., A: []byte, B: []byte &rarr; ..., uint64
- 0 if A is equal to B, else 1. A and B are interpreted as big-endian unsigned integers
- Availability: v4
- Stack: ..., A: uint, B: []byte, C: uint, D: []byte, E: uint64, F: uint64 &rarr; ..., uint64
- Not equal, 1 if true, else 0. B and D are interpreted as big-endian unsigned integers.
- Availability: v9

wB = (-1)^E * widthB ; wD = (-1)^F * widthD
(-1)^A * B * 10^wB != (-1)^C * D * 10^wD. widthB and widthD are uint.

## b%

Expand Down Expand Up @@ -1340,6 +1370,42 @@ The notation A,B indicates that A and B are interpreted as a uint128 value, with
- zero filled byte-array of length A
- Availability: v4

## bexp widthB widthY

- Opcode: 0x??
- Stack: ..., A: uint, B: []byte, E: uint64, F: uint64 &rarr; ..., Y: []byte
- e to the power of a decimal. B is interpreted as big-endian unsigned integers.
- **Cost**: base cost plus cost dependent on widthY
- Availability: v9

wB = (-1)^E * widthB ; wY = (-1)^F * widthY
exp[(-1)^A * B * 10^wB] = Y * 10^wY. widthB and widthY are uint64. widthY output precision is guaranteed.
Calculation is based on the Taylor expansion of e^q.

## bln widthA widthY

- Opcode: 0x??
- Stack: ..., A: []byte, E: uint64, F: uint64 &rarr; ..., X: uint, Y: []byte
- Natural logarithm of a decimal. A is interpreted as big-endian unsigned integers.
- **Cost**: base cost plus cost dependent on widthY
- Availability: v9

wA = (-1)^E * widthA ; wY = (-1)^F * widthY
ln[A * 10^wA] = (-1)^X * Y * 10^wY. widthA and widthY are uint64. widthY output precision is guaranteed.
Calculation is based on the following identity: ln(q) = log2(q) / log2(e)

## bsin widthB widthY

- Opcode: 0x??
- Stack: ..., A: uint, B: []byte, E: uint64, F: uint64 &rarr; ..., X: uint, Y: []byte
- Decimal to the power of a decimal. B and Y are interpreted as big-endian unsigned integers.
- **Cost**: base cost plus cost dependent on widthY
- Availability: v9

wB = (-1)^E * widthB ; wY = (-1)^F * widthY
sin((-1)^A * B * 10^wB) = (-1)^X * Y * 10^wY. widthB and widthY are uint64. widthY output precision is guaranteed.
Calculation is based on the Taylor expansion of sin(q).

## log

- Opcode: 0xb0
Expand Down