Skip to content

Commit

Permalink
update math and numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
joe-p committed Jan 28, 2024
1 parent ec18c47 commit 17992a9
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 49 deletions.
32 changes: 21 additions & 11 deletions docusaurus/docs/guides/math.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,40 @@ It is important to note that `number` in TEALScript represents `uint64`. This me

## Opcode Cost

Every app call has a limited compute budget, measured by opcode budget. Working with the native AVM number type in TEALScript (`uint64`) is the most efficient in terms of opcode cost.

Performing math operations with a integer with a width less than 64 bits is **2x more expensive** than working with the same value as `uint64`. Performing math operations with a integer width more than 64 bits can be up to **20x more expensive** (see table below). As such, if you find yourself running out of opcode budget, it is best to manually cast to `uint64` and then cast back when possible.
Performing math operations with a integer width more than 64 bits can be up to **20x more expensive** (see table below). As such, if you find yourself running out of opcode budget, it is best to manually cast to `uint64` and then cast back when possible.

### Opcode Costs

| Bit Width | Operations | Cost |
| --------- | ---------- | ---- |
| 64 | `+` or `-` | 1 |
| 64 | `*` or `/` | 1 |
| < 64 | `+` or `-` | 2 |
| < 64 | `*` or `/` | 2 |
| > 64 | `+` or `-` | 10 |
| > 64 | `*` or `/` | 20 |
| `<= 64` | `+` or `-` | 1 |
| `<= 64` | `*` or `/` | 1 |
| `> 64` | `+` or `-` | 10 |
| `> 64` | `*` or `/` | 20 |

## Overflows

The AVM will panic if the result of arithmetic with two `uint64` value is larger than 64 bits. This means the AVM has native overflow checks for `uint64`. Other bit widths, however, do not have native overflow protection. This means that some of the opcode budget is burned when perorming overflow checks for these types, making arithemtic with non-`uint64` numbers even more expensive overall.
### Runtime

During runtime, TEALscript will not perform overflow checks. This means you will only encouter an overflow panic when performing math operations and the following max values are exceeded

| Bit Width | Max Value |
| --------- | --------- |
| `<= 64` | `2^64 - 1` |
| `> 64` | `2^512 - 1` |

### Encoding

Prior to encoding a number, TEALScript will ensure that the value does not exceed the respective max value. For example, it will check a `uint8` is not more than `2^8 - 1` prior to encoding it.

### Underflows

Any operation that results in a value less than 0 will cause a panic in the AVM.

## Wide Ratio

A common operation in contracts is to perform division to get the ratio between two numbers (ie. in a liquidty pool). If the numerator and/or divisor includes multiplication of `uint64` values, they might be larger than `uint64` (thus cause an overflow panic) even if the final result of the division would fit in a `uint64`. To handle such cases, TEALScript implements a global function called `wideRatio`.


### Example

```ts
Expand Down
39 changes: 1 addition & 38 deletions docusaurus/docs/guides/types/numbers.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,43 +46,6 @@ const n = 1.23 // ERROR: Missing type
const n: ufixed<64, 2> = 1.234 // ERROR: Precision of 2 decimals places, but 3 are given
```

## Type casting

You can cast types of one number to another (but only `uint` -> `uint` or `ufixed` -> `ufixed`). The compiler will automatically pad smaller values to bigger ones where applicable (such as return values), but will throw an runtime error if there is a value overflow when going from a bigger width to a smaller width.

### Examples

#### Correct: Implicit Padding
```ts
foo(): uint16 {
const n: uint8 = 1
return n // Compiler will convert n (0x01) to uint16 (0x0001)
}
```

#### Correct: Explicit Bit Reduction
```ts
foo(): uint8 {
const n: uint16 = 1
return n // Compiler will convert n (0x0001) to uint8 (0x01). Runtime error if there is an overflow.
```
## Math

You can use standard math operators (`+`, `-`, `/`, `*`, `%`) on any type of numner as long as both operands are the same. Exponents (`**`) work as long as the power is 2^64 or less.
### Overflows
During runtime, there will be an overflow check upon storage of values, returning values, or type casting. This means there is no type checking of intermediate values of math operations. This means the following example will NOT throw an error, even though the intermediate value of `a + b` is larger than the max `uint8` value.
```ts
const a: uint8 = 255
const b: uint8 = 1
const c = a + b - b
```
The only exception to intermediate arithmetic overflows is if the value is larger than 2^512 because this is the largest value supported by the AVM.
### Underflows
Any operation that results in a value less than 0 will cause a panic in the AVM.
See [math](../math.md)

0 comments on commit 17992a9

Please sign in to comment.