Skip to content

Commit 9469346

Browse files
feat(stdlib): Add abs, neg, isNaN, isInfinite to Float64 (#2117)
Co-authored-by: Oscar Spencer <oscar@grain-lang.org>
1 parent ff280a1 commit 9469346

File tree

3 files changed

+283
-16
lines changed

3 files changed

+283
-16
lines changed

compiler/test/stdlib/float64.test.gr

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,35 @@ assert !(5.0d > 5.0d)
3333
assert !(5.0d >= 22.0d)
3434
assert !(5.0d < -17.0d)
3535
assert !(5.0d <= 4.0d)
36+
37+
// isNaN
38+
assert Float64.isNaN(NaNd)
39+
assert Float64.isNaN(1.0d) == false
40+
assert Float64.isNaN(0.0d) == false
41+
assert Float64.isNaN(-1.0d) == false
42+
assert Float64.isNaN(25.76d) == false
43+
assert Float64.isNaN(-25.00d) == false
44+
assert Float64.isNaN(Infinityd) == false
45+
assert Float64.isNaN(-Infinityd) == false
46+
47+
// isInfinite
48+
assert Float64.isInfinite(Infinityd)
49+
assert Float64.isInfinite(-Infinityd)
50+
assert Float64.isInfinite(NaNd) == false
51+
assert Float64.isInfinite(1.0d) == false
52+
assert Float64.isInfinite(0.0d) == false
53+
assert Float64.isInfinite(-1.0d) == false
54+
assert Float64.isInfinite(25.76d) == false
55+
assert Float64.isInfinite(-25.00d) == false
56+
57+
// abs
58+
assert Float64.abs(-25.5d) == 25.5d
59+
assert Float64.abs(25.5d) == 25.5d
60+
assert Float64.isNaN(Float64.abs(NaNd))
61+
assert Float64.abs(Infinityd) == Infinityd
62+
63+
// neg
64+
assert Float64.neg(-25.5d) == 25.5d
65+
assert Float64.neg(25.5d) == -25.5d
66+
assert Float64.isNaN(-NaNd)
67+
assert Float64.neg(Infinityd) == -Infinityd

stdlib/float64.gr

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ use Numbers.{
2424
coerceFloat64ToNumber as toNumber,
2525
}
2626

27+
@unsafe
28+
let _VALUE_OFFSET = 8n
29+
2730
/**
2831
* Infinity represented as a Float64 value.
2932
* This is an alternative to the `Infinityd` literal.
@@ -81,8 +84,8 @@ provide { fromNumber, toNumber }
8184
*/
8285
@unsafe
8386
provide let (+) = (x: Float64, y: Float64) => {
84-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
85-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
87+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
88+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
8689
let ptr = newFloat64(xv + yv)
8790
WasmI32.toGrain(ptr): Float64
8891
}
@@ -103,8 +106,8 @@ provide let (+) = (x: Float64, y: Float64) => {
103106
*/
104107
@unsafe
105108
provide let (-) = (x: Float64, y: Float64) => {
106-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
107-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
109+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
110+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
108111
let ptr = newFloat64(xv - yv)
109112
WasmI32.toGrain(ptr): Float64
110113
}
@@ -125,8 +128,8 @@ provide let (-) = (x: Float64, y: Float64) => {
125128
*/
126129
@unsafe
127130
provide let (*) = (x: Float64, y: Float64) => {
128-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
129-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
131+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
132+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
130133
let ptr = newFloat64(xv * yv)
131134
WasmI32.toGrain(ptr): Float64
132135
}
@@ -147,8 +150,8 @@ provide let (*) = (x: Float64, y: Float64) => {
147150
*/
148151
@unsafe
149152
provide let (/) = (x: Float64, y: Float64) => {
150-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
151-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
153+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
154+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
152155
let ptr = newFloat64(xv / yv)
153156
WasmI32.toGrain(ptr): Float64
154157
}
@@ -169,8 +172,8 @@ provide let (/) = (x: Float64, y: Float64) => {
169172
*/
170173
@unsafe
171174
provide let (<) = (x: Float64, y: Float64) => {
172-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
173-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
175+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
176+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
174177
xv < yv
175178
}
176179

@@ -190,8 +193,8 @@ provide let (<) = (x: Float64, y: Float64) => {
190193
*/
191194
@unsafe
192195
provide let (>) = (x: Float64, y: Float64) => {
193-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
194-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
196+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
197+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
195198
xv > yv
196199
}
197200

@@ -215,8 +218,8 @@ provide let (>) = (x: Float64, y: Float64) => {
215218
*/
216219
@unsafe
217220
provide let (<=) = (x: Float64, y: Float64) => {
218-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
219-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
221+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
222+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
220223
xv <= yv
221224
}
222225

@@ -240,7 +243,75 @@ provide let (<=) = (x: Float64, y: Float64) => {
240243
*/
241244
@unsafe
242245
provide let (>=) = (x: Float64, y: Float64) => {
243-
let xv = WasmF64.load(WasmI32.fromGrain(x), 8n)
244-
let yv = WasmF64.load(WasmI32.fromGrain(y), 8n)
246+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
247+
let yv = WasmF64.load(WasmI32.fromGrain(y), _VALUE_OFFSET)
245248
xv >= yv
246249
}
250+
251+
/**
252+
* Checks if the value is a float NaN value (Not A Number).
253+
*
254+
* @param x: The value to check
255+
* @returns `true` if the value is NaN, otherwise `false`
256+
*
257+
* @example Float64.isNaN(NaNd)
258+
* @example Float64.isNaN(Infinityd) == false
259+
* @example Float64.isNaN(-Infinityd) == false
260+
* @example Float64.isNaN(0.5d) == false
261+
* @example Float64.isNaN(1.0d) == false
262+
*
263+
* @since v0.6.5
264+
*/
265+
provide let isNaN = (x: Float64) => x != x
266+
267+
/**
268+
* Checks if a float is infinite, that is either of positive or negative infinity.
269+
*
270+
* @param x: The value to check
271+
* @returns `true` if the value is infinite or `false` otherwise
272+
*
273+
* @example Float64.isInfinite(Infinityd)
274+
* @example Float64.isInfinite(-Infinityd)
275+
* @example Float64.isInfinite(NaNd) == false
276+
* @example Float64.isInfinite(0.5d) == false
277+
* @example Float64.isInfinite(1.0d) == false
278+
*
279+
* @since v0.6.5
280+
*/
281+
provide let isInfinite = (x: Float64) => x == Infinityd || x == -Infinityd
282+
283+
/**
284+
* Returns the absolute value. That is, it returns `x` if `x` is positive or zero and the negation of `x` if `x` is negative.
285+
*
286+
* @param x: The operand
287+
* @returns The absolute value of the operand
288+
*
289+
* @example Float64.abs(-1.0d) == 1.0d
290+
* @example Float64.abs(5.0d) == 5.0d
291+
*
292+
* @since v0.6.5
293+
*/
294+
@unsafe
295+
provide let abs = (x: Float64) => {
296+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
297+
let ptr = newFloat64(WasmF64.abs(xv))
298+
WasmI32.toGrain(ptr): Float64
299+
}
300+
301+
/**
302+
* Returns the negation of its operand.
303+
*
304+
* @param x: The operand
305+
* @returns The negated operand
306+
*
307+
* @example Float64.neg(-1.0d) == 1.0d
308+
* @example Float64.neg(1.0d) == -1.0d
309+
*
310+
* @since v0.6.5
311+
*/
312+
@unsafe
313+
provide let neg = (x: Float64) => {
314+
let xv = WasmF64.load(WasmI32.fromGrain(x), _VALUE_OFFSET)
315+
let ptr = newFloat64(WasmF64.neg(xv))
316+
WasmI32.toGrain(ptr): Float64
317+
}

stdlib/float64.md

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,167 @@ use Float64.{ (>=) }
480480
assert -1.0d >= -1.0d
481481
```
482482

483+
### Float64.**isNaN**
484+
485+
<details disabled>
486+
<summary tabindex="-1">Added in <code>next</code></summary>
487+
No other changes yet.
488+
</details>
489+
490+
```grain
491+
isNaN : (x: Float64) => Bool
492+
```
493+
494+
Checks if the value is a float NaN value (Not A Number).
495+
496+
Parameters:
497+
498+
|param|type|description|
499+
|-----|----|-----------|
500+
|`x`|`Float64`|The value to check|
501+
502+
Returns:
503+
504+
|type|description|
505+
|----|-----------|
506+
|`Bool`|`true` if the value is NaN, otherwise `false`|
507+
508+
Examples:
509+
510+
```grain
511+
Float64.isNaN(NaNd)
512+
```
513+
514+
```grain
515+
Float64.isNaN(Infinityd) == false
516+
```
517+
518+
```grain
519+
Float64.isNaN(-Infinityd) == false
520+
```
521+
522+
```grain
523+
Float64.isNaN(0.5d) == false
524+
```
525+
526+
```grain
527+
Float64.isNaN(1.0d) == false
528+
```
529+
530+
### Float64.**isInfinite**
531+
532+
<details disabled>
533+
<summary tabindex="-1">Added in <code>next</code></summary>
534+
No other changes yet.
535+
</details>
536+
537+
```grain
538+
isInfinite : (x: Float64) => Bool
539+
```
540+
541+
Checks if a float is infinite, that is either of positive or negative infinity.
542+
543+
Parameters:
544+
545+
|param|type|description|
546+
|-----|----|-----------|
547+
|`x`|`Float64`|The value to check|
548+
549+
Returns:
550+
551+
|type|description|
552+
|----|-----------|
553+
|`Bool`|`true` if the value is infinite or `false` otherwise|
554+
555+
Examples:
556+
557+
```grain
558+
Float64.isInfinite(Infinityd)
559+
```
560+
561+
```grain
562+
Float64.isInfinite(-Infinityd)
563+
```
564+
565+
```grain
566+
Float64.isInfinite(NaNd) == false
567+
```
568+
569+
```grain
570+
Float64.isInfinite(0.5d) == false
571+
```
572+
573+
```grain
574+
Float64.isInfinite(1.0d) == false
575+
```
576+
577+
### Float64.**abs**
578+
579+
<details disabled>
580+
<summary tabindex="-1">Added in <code>next</code></summary>
581+
No other changes yet.
582+
</details>
583+
584+
```grain
585+
abs : (x: Float64) => Float64
586+
```
587+
588+
Returns the absolute value. That is, it returns `x` if `x` is positive or zero and the negation of `x` if `x` is negative.
589+
590+
Parameters:
591+
592+
|param|type|description|
593+
|-----|----|-----------|
594+
|`x`|`Float64`|The operand|
595+
596+
Returns:
597+
598+
|type|description|
599+
|----|-----------|
600+
|`Float64`|The absolute value of the operand|
601+
602+
Examples:
603+
604+
```grain
605+
Float64.abs(-1.0d) == 1.0d
606+
```
607+
608+
```grain
609+
Float64.abs(5.0d) == 5.0d
610+
```
611+
612+
### Float64.**neg**
613+
614+
<details disabled>
615+
<summary tabindex="-1">Added in <code>next</code></summary>
616+
No other changes yet.
617+
</details>
618+
619+
```grain
620+
neg : (x: Float64) => Float64
621+
```
622+
623+
Returns the negation of its operand.
624+
625+
Parameters:
626+
627+
|param|type|description|
628+
|-----|----|-----------|
629+
|`x`|`Float64`|The operand|
630+
631+
Returns:
632+
633+
|type|description|
634+
|----|-----------|
635+
|`Float64`|The negated operand|
636+
637+
Examples:
638+
639+
```grain
640+
Float64.neg(-1.0d) == 1.0d
641+
```
642+
643+
```grain
644+
Float64.neg(1.0d) == -1.0d
645+
```
646+

0 commit comments

Comments
 (0)