Skip to content

Commit

Permalink
feat(stdlib): Add abs, neg, isNaN, isInfinite to Float64 (#…
Browse files Browse the repository at this point in the history
…2117)

Co-authored-by: Oscar Spencer <oscar@grain-lang.org>
  • Loading branch information
spotandjake and ospencer authored Jul 28, 2024
1 parent ff280a1 commit 9469346
Show file tree
Hide file tree
Showing 3 changed files with 283 additions and 16 deletions.
32 changes: 32 additions & 0 deletions compiler/test/stdlib/float64.test.gr
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,35 @@ assert !(5.0d > 5.0d)
assert !(5.0d >= 22.0d)
assert !(5.0d < -17.0d)
assert !(5.0d <= 4.0d)

// isNaN
assert Float64.isNaN(NaNd)
assert Float64.isNaN(1.0d) == false
assert Float64.isNaN(0.0d) == false
assert Float64.isNaN(-1.0d) == false
assert Float64.isNaN(25.76d) == false
assert Float64.isNaN(-25.00d) == false
assert Float64.isNaN(Infinityd) == false
assert Float64.isNaN(-Infinityd) == false

// isInfinite
assert Float64.isInfinite(Infinityd)
assert Float64.isInfinite(-Infinityd)
assert Float64.isInfinite(NaNd) == false
assert Float64.isInfinite(1.0d) == false
assert Float64.isInfinite(0.0d) == false
assert Float64.isInfinite(-1.0d) == false
assert Float64.isInfinite(25.76d) == false
assert Float64.isInfinite(-25.00d) == false

// abs
assert Float64.abs(-25.5d) == 25.5d
assert Float64.abs(25.5d) == 25.5d
assert Float64.isNaN(Float64.abs(NaNd))
assert Float64.abs(Infinityd) == Infinityd

// neg
assert Float64.neg(-25.5d) == 25.5d
assert Float64.neg(25.5d) == -25.5d
assert Float64.isNaN(-NaNd)
assert Float64.neg(Infinityd) == -Infinityd
103 changes: 87 additions & 16 deletions stdlib/float64.gr
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ use Numbers.{
coerceFloat64ToNumber as toNumber,
}

@unsafe
let _VALUE_OFFSET = 8n

/**
* Infinity represented as a Float64 value.
* This is an alternative to the `Infinityd` literal.
Expand Down Expand Up @@ -81,8 +84,8 @@ provide { fromNumber, toNumber }
*/
@unsafe
provide let (+) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
let ptr = newFloat64(xv + yv)
WasmI32.toGrain(ptr): Float64
}
Expand All @@ -103,8 +106,8 @@ provide let (+) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (-) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
let ptr = newFloat64(xv - yv)
WasmI32.toGrain(ptr): Float64
}
Expand All @@ -125,8 +128,8 @@ provide let (-) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (*) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
let ptr = newFloat64(xv * yv)
WasmI32.toGrain(ptr): Float64
}
Expand All @@ -147,8 +150,8 @@ provide let (*) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (/) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
let ptr = newFloat64(xv / yv)
WasmI32.toGrain(ptr): Float64
}
Expand All @@ -169,8 +172,8 @@ provide let (/) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (<) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
xv < yv
}

Expand All @@ -190,8 +193,8 @@ provide let (<) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (>) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
xv > yv
}

Expand All @@ -215,8 +218,8 @@ provide let (>) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (<=) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
xv <= yv
}

Expand All @@ -240,7 +243,75 @@ provide let (<=) = (x: Float64, y: Float64) => {
*/
@unsafe
provide let (>=) = (x: Float64, y: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
xv >= yv
}

/**
* Checks if the value is a float NaN value (Not A Number).
*
* @param x: The value to check
* @returns `true` if the value is NaN, otherwise `false`
*
* @example Float64.isNaN(NaNd)
* @example Float64.isNaN(Infinityd) == false
* @example Float64.isNaN(-Infinityd) == false
* @example Float64.isNaN(0.5d) == false
* @example Float64.isNaN(1.0d) == false
*
* @since v0.6.5
*/
provide let isNaN = (x: Float64) => x != x

/**
* Checks if a float is infinite, that is either of positive or negative infinity.
*
* @param x: The value to check
* @returns `true` if the value is infinite or `false` otherwise
*
* @example Float64.isInfinite(Infinityd)
* @example Float64.isInfinite(-Infinityd)
* @example Float64.isInfinite(NaNd) == false
* @example Float64.isInfinite(0.5d) == false
* @example Float64.isInfinite(1.0d) == false
*
* @since v0.6.5
*/
provide let isInfinite = (x: Float64) => x == Infinityd || x == -Infinityd

/**
* Returns the absolute value. That is, it returns `x` if `x` is positive or zero and the negation of `x` if `x` is negative.
*
* @param x: The operand
* @returns The absolute value of the operand
*
* @example Float64.abs(-1.0d) == 1.0d
* @example Float64.abs(5.0d) == 5.0d
*
* @since v0.6.5
*/
@unsafe
provide let abs = (x: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let ptr = newFloat64(WasmF64.abs(xv))
WasmI32.toGrain(ptr): Float64
}

/**
* Returns the negation of its operand.
*
* @param x: The operand
* @returns The negated operand
*
* @example Float64.neg(-1.0d) == 1.0d
* @example Float64.neg(1.0d) == -1.0d
*
* @since v0.6.5
*/
@unsafe
provide let neg = (x: Float64) => {
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
let ptr = newFloat64(WasmF64.neg(xv))
WasmI32.toGrain(ptr): Float64
}
164 changes: 164 additions & 0 deletions stdlib/float64.md
Original file line number Diff line number Diff line change
Expand Up @@ -480,3 +480,167 @@ use Float64.{ (>=) }
assert -1.0d >= -1.0d
```

### Float64.**isNaN**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
isNaN : (x: Float64) => Bool
```

Checks if the value is a float NaN value (Not A Number).

Parameters:

|param|type|description|
|-----|----|-----------|
|`x`|`Float64`|The value to check|

Returns:

|type|description|
|----|-----------|
|`Bool`|`true` if the value is NaN, otherwise `false`|

Examples:

```grain
Float64.isNaN(NaNd)
```

```grain
Float64.isNaN(Infinityd) == false
```

```grain
Float64.isNaN(-Infinityd) == false
```

```grain
Float64.isNaN(0.5d) == false
```

```grain
Float64.isNaN(1.0d) == false
```

### Float64.**isInfinite**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
isInfinite : (x: Float64) => Bool
```

Checks if a float is infinite, that is either of positive or negative infinity.

Parameters:

|param|type|description|
|-----|----|-----------|
|`x`|`Float64`|The value to check|

Returns:

|type|description|
|----|-----------|
|`Bool`|`true` if the value is infinite or `false` otherwise|

Examples:

```grain
Float64.isInfinite(Infinityd)
```

```grain
Float64.isInfinite(-Infinityd)
```

```grain
Float64.isInfinite(NaNd) == false
```

```grain
Float64.isInfinite(0.5d) == false
```

```grain
Float64.isInfinite(1.0d) == false
```

### Float64.**abs**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
abs : (x: Float64) => Float64
```

Returns the absolute value. That is, it returns `x` if `x` is positive or zero and the negation of `x` if `x` is negative.

Parameters:

|param|type|description|
|-----|----|-----------|
|`x`|`Float64`|The operand|

Returns:

|type|description|
|----|-----------|
|`Float64`|The absolute value of the operand|

Examples:

```grain
Float64.abs(-1.0d) == 1.0d
```

```grain
Float64.abs(5.0d) == 5.0d
```

### Float64.**neg**

<details disabled>
<summary tabindex="-1">Added in <code>next</code></summary>
No other changes yet.
</details>

```grain
neg : (x: Float64) => Float64
```

Returns the negation of its operand.

Parameters:

|param|type|description|
|-----|----|-----------|
|`x`|`Float64`|The operand|

Returns:

|type|description|
|----|-----------|
|`Float64`|The negated operand|

Examples:

```grain
Float64.neg(-1.0d) == 1.0d
```

```grain
Float64.neg(1.0d) == -1.0d
```

0 comments on commit 9469346

Please sign in to comment.