• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kos-lang / kos / 28804370359

06 Jul 2026 01:33PM UTC coverage: 95.093% (-1.3%) from 96.422%
28804370359

push

github

cdragan
net: use poll() instead of select()

select() has a limit of 1024 fd values, for any fds which are higher
than 1024 select() can't work.

7 of 13 new or added lines in 1 file covered. (53.85%)

884 existing lines in 19 files now uncovered.

24707 of 25982 relevant lines covered (95.09%)

939477.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.32
/modules/kos_mod_math.c
1
/* SPDX-License-Identifier: MIT
2
 * SPDX-FileCopyrightText: Copyright (c) 2014-2026 Chris Dragan
3
 */
4

5
#include "../inc/kos_array.h"
6
#include "../inc/kos_constants.h"
7
#include "../inc/kos_entity.h"
8
#include "../inc/kos_error.h"
9
#include "../inc/kos_instance.h"
10
#include "../inc/kos_module.h"
11
#include "../inc/kos_string.h"
12
#include "../inc/kos_utils.h"
13
#include "../core/kos_misc.h"
14
#include "../core/kos_try.h"
15
#include <math.h>
16

17
static const char str_err_abs_minus_max[] = "cannot calculate abs of the lowest integer value";
18
static const char str_err_m1_or_less[]    = "value is not greater than -1";
19
static const char str_err_negative_root[] = "invalid base";
20
KOS_DECLARE_STATIC_CONST_STRING(str_err_not_number, "object is not a number");
21
static const char str_err_outside_m1_1[]  = "value outside of [-1, 1] range";
22
KOS_DECLARE_STATIC_CONST_STRING(str_err_pow_0_minus, "zero cannot be raised to negative power");
23
static const char str_err_zero_or_less[]  = "value is not positive";
24

25
/* @item math abs()
26
 *
27
 *     abs(number)
28
 *
29
 * Returns absolute value of `number`.
30
 *
31
 * Preserves the type of the input argument (integer or float).
32
 *
33
 * If `number` is an integer and it is the lowest possible integer value
34
 * (`0x8000_0000_0000_0000`), then throws an exception.
35
 *
36
 * Examples:
37
 *
38
 *     > math.abs(-100)
39
 *     100
40
 *     > math.abs(-math.infinity)
41
 *     infinity
42
 */
43
static KOS_OBJ_ID kos_abs(const KOS_CONTEXT             ctx,
30✔
44
                          const KOS_OBJ_ID              this_obj,
45
                          const uint32_t                num_args,
46
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
47
{
48
    KOS_NUMERIC numeric = KOS_get_numeric(args[0]);
30✔
49
    KOS_OBJ_ID  ret     = KOS_BADPTR;
30✔
50

51
    if (numeric.type == KOS_INTEGER_VALUE) {
30✔
52
        if (numeric.u.i == (int64_t)((uint64_t)1U << 63))
16✔
53
            KOS_raise_exception_cstring(ctx, str_err_abs_minus_max);
×
54
        else
55
            ret = KOS_new_int(ctx, numeric.u.i < 0 ? -numeric.u.i : numeric.u.i);
16✔
56
    }
57
    else if (numeric.type == KOS_FLOAT_VALUE) {
14✔
58
        numeric.u.i &= (int64_t)~((uint64_t)1U << 63);
14✔
59

60
        ret = KOS_new_float(ctx, numeric.u.d);
14✔
61
    }
62
    else
63
        KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_number));
×
64

65
    return ret;
30✔
66
}
67

68
/* @item math acos()
69
 *
70
 *     acos(number)
71
 *
72
 * Returns principal value of the arc cosine of `number`.
73
 *
74
 * The returned value is always a float.
75
 *
76
 * Throws an exception if `number` is outside of the [-1, 1] range.
77
 *
78
 * Example:
79
 *
80
 *     > math.acos(1)
81
 *     0.0
82
 */
83
static KOS_OBJ_ID kos_acos(const KOS_CONTEXT             ctx,
9✔
84
                           const KOS_OBJ_ID              this_obj,
85
                           const uint32_t                num_args,
86
                           KOS_ATOMIC(KOS_OBJ_ID) *const args)
87
{
88
    KOS_NUMERIC numeric;
89
    KOS_OBJ_ID  ret   = KOS_BADPTR;
9✔
90
    double      value;
91
    int         error = KOS_SUCCESS;
9✔
92

93
    numeric = KOS_get_numeric(args[0]);
9✔
94

95
    if (numeric.type == KOS_INTEGER_VALUE) {
9✔
96
        if ((numeric.u.i < -1) || (numeric.u.i > 1))
3✔
97
            RAISE_EXCEPTION(str_err_outside_m1_1);
×
98
        value = (double)numeric.u.i;
3✔
99
    }
100
    else if (numeric.type == KOS_FLOAT_VALUE) {
6✔
101
        value = numeric.u.d;
6✔
102
        if ((value < -1) || (value > 1))
6✔
103
            RAISE_EXCEPTION(str_err_outside_m1_1);
5✔
104
    }
105
    else
106
        RAISE_EXCEPTION_STR(str_err_not_number);
×
107

108
    ret = KOS_new_float(ctx, acos(value));
4✔
109

110
cleanup:
9✔
111
    return error ? KOS_BADPTR : ret;
9✔
112
}
113

114
/* @item math asin()
115
 *
116
 *     asin(number)
117
 *
118
 * Returns principal value of the arc sine of `number`.
119
 *
120
 * The returned value is always a float.
121
 *
122
 * Throws an exception if `number` is outside of the [-1, 1] range.
123
 *
124
 * Example:
125
 *
126
 *     > math.asin(-1)
127
 *     0.0
128
 */
129
static KOS_OBJ_ID kos_asin(const KOS_CONTEXT             ctx,
9✔
130
                           const KOS_OBJ_ID              this_obj,
131
                           const uint32_t                num_args,
132
                           KOS_ATOMIC(KOS_OBJ_ID) *const args)
133
{
134
    KOS_NUMERIC numeric;
135
    KOS_OBJ_ID  ret   = KOS_BADPTR;
9✔
136
    double      value;
137
    int         error = KOS_SUCCESS;
9✔
138

139
    numeric = KOS_get_numeric(args[0]);
9✔
140

141
    if (numeric.type == KOS_INTEGER_VALUE) {
9✔
142
        if ((numeric.u.i < -1) || (numeric.u.i > 1))
3✔
143
            RAISE_EXCEPTION(str_err_outside_m1_1);
×
144
        value = (double)numeric.u.i;
3✔
145
    }
146
    else if (numeric.type == KOS_FLOAT_VALUE) {
6✔
147
        value = numeric.u.d;
6✔
148
        if ((value < -1) || (value > 1))
6✔
149
            RAISE_EXCEPTION(str_err_outside_m1_1);
5✔
150
    }
151
    else
152
        RAISE_EXCEPTION_STR(str_err_not_number);
×
153

154
    ret = KOS_new_float(ctx, asin(value));
4✔
155

156
cleanup:
9✔
157
    return error ? KOS_BADPTR : ret;
9✔
158
}
159

160
/* @item math atan()
161
 *
162
 *     atan(number)
163
 *
164
 * Returns principal value of the arc tangent of `number`.
165
 *
166
 * The returned value is always a float.
167
 *
168
 * Example:
169
 *
170
 *     > math.atan(math.infinity)
171
 *     1.570796326794897
172
 */
173
static KOS_OBJ_ID kos_atan(const KOS_CONTEXT             ctx,
7✔
174
                           const KOS_OBJ_ID              this_obj,
175
                           const uint32_t                num_args,
176
                           KOS_ATOMIC(KOS_OBJ_ID) *const args)
177
{
178
    KOS_NUMERIC numeric;
179
    KOS_OBJ_ID  ret   = KOS_BADPTR;
7✔
180
    double      value;
181
    int         error = KOS_SUCCESS;
7✔
182

183
    numeric = KOS_get_numeric(args[0]);
7✔
184

185
    if (numeric.type == KOS_INTEGER_VALUE)
7✔
186
        value = (double)numeric.u.i;
3✔
187
    else if (numeric.type == KOS_FLOAT_VALUE)
4✔
188
        value = numeric.u.d;
4✔
189
    else
190
        RAISE_EXCEPTION_STR(str_err_not_number);
×
191

192
    ret = KOS_new_float(ctx, atan(value));
7✔
193

194
cleanup:
7✔
195
    return error ? KOS_BADPTR : ret;
7✔
196
}
197

198
/* @item math ceil()
199
 *
200
 *     ceil(number)
201
 *
202
 * Rounds a number to the closest, but higher or equal integer value.
203
 *
204
 * Preserves the type of the input argument.  If `number` is an integer,
205
 * returns that integer.  If `number` is a float, returns a rounded float.
206
 *
207
 * Examples:
208
 *
209
 *     > math.ceil(10.5)
210
 *     11.0
211
 *     > math.ceil(-0.1)
212
 *     -0.0
213
 */
214
static KOS_OBJ_ID kos_ceil(const KOS_CONTEXT             ctx,
6✔
215
                           const KOS_OBJ_ID              this_obj,
216
                           const uint32_t                num_args,
217
                           KOS_ATOMIC(KOS_OBJ_ID) *const args)
218
{
219
    KOS_OBJ_ID ret = KOS_BADPTR;
6✔
220

221
    if (IS_SMALL_INT(args[0]))
6✔
222
        ret = args[0];
1✔
223

224
    else switch (READ_OBJ_TYPE(args[0])) {
5✔
225

226
        case OBJ_INTEGER:
1✔
227
            ret = args[0];
1✔
228
            break;
1✔
229

230
        case OBJ_FLOAT:
3✔
231
            if (KOS_is_nan(args[0]) || KOS_is_infinity(args[0]))
3✔
232
                ret = args[0];
2✔
233
            else
234
                ret = KOS_new_float(ctx, ceil(OBJPTR(FLOAT, args[0])->value));
1✔
235
            break;
3✔
236

237
        default:
1✔
238
            KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_number));
1✔
239
            break;
1✔
240
    }
241

242
    return ret;
6✔
243
}
244

245
/* @item math cos()
246
 *
247
 *     cos(number)
248
 *
249
 * Returns cosine of `number`.
250
 *
251
 * The returned value is always a float.
252
 *
253
 * Example:
254
 *
255
 *     > math.cos(math.pi / 2)
256
 *     0.0
257
 */
258
static KOS_OBJ_ID kos_cos(const KOS_CONTEXT             ctx,
8✔
259
                          const KOS_OBJ_ID              this_obj,
260
                          const uint32_t                num_args,
261
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
262
{
263
    KOS_NUMERIC numeric;
264
    KOS_OBJ_ID  ret   = KOS_BADPTR;
8✔
265
    double      value;
266
    int         error = KOS_SUCCESS;
8✔
267

268
    numeric = KOS_get_numeric(args[0]);
8✔
269

270
    if (numeric.type == KOS_INTEGER_VALUE)
8✔
271
        value = (double)numeric.u.i;
1✔
272
    else if (numeric.type == KOS_FLOAT_VALUE)
7✔
273
        value = numeric.u.d;
7✔
274
    else
UNCOV
275
        RAISE_EXCEPTION_STR(str_err_not_number);
×
276

277
    ret = KOS_new_float(ctx, cos(value));
8✔
278

279
cleanup:
8✔
280
    return error ? KOS_BADPTR : ret;
8✔
281
}
282

283
/* @item math exp()
284
 *
285
 *     exp(number)
286
 *
287
 * Returns Eulers number *e* raised to the power of `number`.
288
 *
289
 * The value returned is always a float.
290
 *
291
 * Examples:
292
 *
293
 *     > math.exp(1)
294
 *     2.718281828459045
295
 *     > math.exp(-1)
296
 *     0.367879441171442
297
 */
298
static KOS_OBJ_ID kos_exp(const KOS_CONTEXT             ctx,
9✔
299
                          const KOS_OBJ_ID              this_obj,
300
                          const uint32_t                num_args,
301
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
302
{
303
    KOS_NUMERIC numeric;
304
    KOS_OBJ_ID  ret   = KOS_BADPTR;
9✔
305
    double      value;
306
    int         error = KOS_SUCCESS;
9✔
307

308
    numeric = KOS_get_numeric(args[0]);
9✔
309

310
    if (numeric.type == KOS_INTEGER_VALUE)
9✔
311
        value = (double)numeric.u.i;
3✔
312
    else if (numeric.type == KOS_FLOAT_VALUE)
6✔
313
        value = numeric.u.d;
3✔
314
    else
315
        RAISE_EXCEPTION_STR(str_err_not_number);
3✔
316

317
    ret = KOS_new_float(ctx, exp(value));
6✔
318

319
cleanup:
9✔
320
    return error ? KOS_BADPTR : ret;
9✔
321
}
322

323
/* @item math expm1()
324
 *
325
 *     expm1(number)
326
 *
327
 * Returns Euler's number *e* raised to the power of `number` and subtracts `1`.
328
 *
329
 * The returned value returned is always a float.
330
 *
331
 * The returned value has a higher precision than `math.exp(number) - 1`.
332
 *
333
 * Example:
334
 *
335
 *     > math.expm1(2)
336
 *     6.38905609893065
337
 */
338
static KOS_OBJ_ID kos_expm1(const KOS_CONTEXT             ctx,
8✔
339
                            const KOS_OBJ_ID              this_obj,
340
                            const uint32_t                num_args,
341
                            KOS_ATOMIC(KOS_OBJ_ID) *const args)
342
{
343
    KOS_NUMERIC numeric;
344
    KOS_OBJ_ID  ret   = KOS_BADPTR;
8✔
345
    double      value;
346
    int         error = KOS_SUCCESS;
8✔
347

348
    numeric = KOS_get_numeric(args[0]);
8✔
349

350
    if (numeric.type == KOS_INTEGER_VALUE)
8✔
351
        value = (double)numeric.u.i;
2✔
352
    else if (numeric.type == KOS_FLOAT_VALUE)
6✔
353
        value = numeric.u.d;
3✔
354
    else
355
        RAISE_EXCEPTION_STR(str_err_not_number);
3✔
356

357
    ret = KOS_new_float(ctx, expm1(value));
5✔
358

359
cleanup:
8✔
360
    return error ? KOS_BADPTR : ret;
8✔
361
}
362

363
/* @item math floor()
364
 *
365
 *     floor(number)
366
 *
367
 * Rounds a number to the closest, but lower or equal integer value.
368
 *
369
 * Preserves the type of the input argument.  If `number` is an integer,
370
 * returns that integer.  If `number` is a float, returns a rounded float.
371
 *
372
 * Examples:
373
 *
374
 *     > math.floor(0.1)
375
 *     0.0
376
 *     > math.floor(-0.1)
377
 *     -1.0
378
 */
379
static KOS_OBJ_ID kos_floor(const KOS_CONTEXT             ctx,
774✔
380
                            const KOS_OBJ_ID              this_obj,
381
                            const uint32_t                num_args,
382
                            KOS_ATOMIC(KOS_OBJ_ID) *const args)
383
{
384
    KOS_OBJ_ID ret = KOS_BADPTR;
774✔
385

386
    if (IS_SMALL_INT(args[0]))
774✔
387
        ret = args[0];
1✔
388

389
    else switch (READ_OBJ_TYPE(args[0])) {
773✔
390

391
        case OBJ_INTEGER:
1✔
392
            ret = args[0];
1✔
393
            break;
1✔
394

395
        case OBJ_FLOAT:
771✔
396
            if (KOS_is_nan(args[0]) || KOS_is_infinity(args[0]))
771✔
397
                ret = args[0];
2✔
398
            else
399
                ret = KOS_new_float(ctx, floor(OBJPTR(FLOAT, args[0])->value));
769✔
400
            break;
771✔
401

402
        default:
1✔
403
            KOS_raise_exception(ctx, KOS_CONST_ID(str_err_not_number));
1✔
404
            break;
1✔
405
    }
406

407
    return ret;
774✔
408
}
409

410
/* @item math log()
411
 *
412
 *     log(number)
413
 *
414
 * Returns natural (base *e*) logarithm of `number`.
415
 *
416
 * The value returned is always a float.
417
 *
418
 * Throws an exception if `number` is 0 or less.
419
 *
420
 * Examples:
421
 *
422
 *     > math.log(1)
423
 *     0.0
424
 */
425
static KOS_OBJ_ID kos_log(const KOS_CONTEXT             ctx,
11✔
426
                          const KOS_OBJ_ID              this_obj,
427
                          const uint32_t                num_args,
428
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
429
{
430
    KOS_NUMERIC numeric;
431
    KOS_OBJ_ID  ret   = KOS_BADPTR;
11✔
432
    double      value;
433
    int         error = KOS_SUCCESS;
11✔
434

435
    numeric = KOS_get_numeric(args[0]);
11✔
436

437
    if (numeric.type == KOS_INTEGER_VALUE) {
11✔
438
        if (numeric.u.i <= 0)
5✔
439
            RAISE_EXCEPTION(str_err_zero_or_less);
3✔
440
        value = (double)numeric.u.i;
2✔
441
    }
442
    else if (numeric.type == KOS_FLOAT_VALUE) {
6✔
443
        value = numeric.u.d;
6✔
444
        if (value <= 0)
6✔
445
            RAISE_EXCEPTION(str_err_zero_or_less);
2✔
446
    }
447
    else
UNCOV
448
        RAISE_EXCEPTION_STR(str_err_not_number);
×
449

450
    ret = KOS_new_float(ctx, log(value));
6✔
451

452
cleanup:
11✔
453
    return error ? KOS_BADPTR : ret;
11✔
454
}
455

456
/* @item math log10()
457
 *
458
 *     log10(number)
459
 *
460
 * Returns base 10 logarithm of `number`.
461
 *
462
 * The value returned is always a float.
463
 *
464
 * Throws an exception if `number` is 0 or less.
465
 *
466
 * Examples:
467
 *
468
 *     > math.log10(1)
469
 *     0.0
470
 *     > math.log10(100)
471
 *     2.0
472
 */
473
static KOS_OBJ_ID kos_log10(const KOS_CONTEXT             ctx,
12✔
474
                            const KOS_OBJ_ID              this_obj,
475
                            const uint32_t                num_args,
476
                            KOS_ATOMIC(KOS_OBJ_ID) *const args)
477
{
478
    KOS_NUMERIC numeric;
479
    KOS_OBJ_ID  ret   = KOS_BADPTR;
12✔
480
    double      value;
481
    int         error = KOS_SUCCESS;
12✔
482

483
    numeric = KOS_get_numeric(args[0]);
12✔
484

485
    if (numeric.type == KOS_INTEGER_VALUE) {
12✔
486
        if (numeric.u.i <= 0)
6✔
487
            RAISE_EXCEPTION(str_err_zero_or_less);
3✔
488
        value = (double)numeric.u.i;
3✔
489
    }
490
    else if (numeric.type == KOS_FLOAT_VALUE) {
6✔
491
        value = numeric.u.d;
6✔
492
        if (value <= 0)
6✔
493
            RAISE_EXCEPTION(str_err_zero_or_less);
2✔
494
    }
495
    else
UNCOV
496
        RAISE_EXCEPTION_STR(str_err_not_number);
×
497

498
    ret = KOS_new_float(ctx, log10(value));
7✔
499

500
cleanup:
12✔
501
    return error ? KOS_BADPTR : ret;
12✔
502
}
503

504
/* @item math log1p()
505
 *
506
 *     log1p(number)
507
 *
508
 * Returns natural (base *e*) logarithm of `1 + number`.
509
 *
510
 * The value returned is always a float.
511
 *
512
 * The returned value has a higher precision than `math.log(number + 1)`.
513
 *
514
 * Throws an exception if `number` is -1 or less.
515
 *
516
 * Examples:
517
 *
518
 *     > math.log1p(0)
519
 *     0.0
520
 */
521
static KOS_OBJ_ID kos_log1p(const KOS_CONTEXT             ctx,
11✔
522
                            const KOS_OBJ_ID              this_obj,
523
                            const uint32_t                num_args,
524
                            KOS_ATOMIC(KOS_OBJ_ID) *const args)
525
{
526
    KOS_NUMERIC numeric;
527
    KOS_OBJ_ID  ret   = KOS_BADPTR;
11✔
528
    double      value;
529
    int         error = KOS_SUCCESS;
11✔
530

531
    numeric = KOS_get_numeric(args[0]);
11✔
532

533
    if (numeric.type == KOS_INTEGER_VALUE) {
11✔
534
        if (numeric.u.i <= -1)
5✔
535
            RAISE_EXCEPTION(str_err_m1_or_less);
3✔
536
        value = (double)numeric.u.i;
2✔
537
    }
538
    else if (numeric.type == KOS_FLOAT_VALUE) {
6✔
539
        value = numeric.u.d;
6✔
540
        if (value <= -1)
6✔
541
            RAISE_EXCEPTION(str_err_m1_or_less);
2✔
542
    }
543
    else
UNCOV
544
        RAISE_EXCEPTION_STR(str_err_not_number);
×
545

546
    ret = KOS_new_float(ctx, log1p(value));
6✔
547

548
cleanup:
11✔
549
    return error ? KOS_BADPTR : ret;
11✔
550
}
551

552
/* @item math is_infinity()
553
 *
554
 *     is_infinity(number)
555
 *
556
 * Returns `true` if the `number` is a float and its value is plus or minus
557
 * infinity, otherwise returns `false`.
558
 *
559
 * Examples:
560
 *
561
 *     > math.is_infinity(math.infinity)
562
 *     true
563
 *     > math.is_infinity(math.nan)
564
 *     false
565
 *     > math.is_infinity(1e60)
566
 *     false
567
 */
568
static KOS_OBJ_ID kos_is_infinity(const KOS_CONTEXT             ctx,
23✔
569
                                  const KOS_OBJ_ID              this_obj,
570
                                  const uint32_t                num_args,
571
                                  KOS_ATOMIC(KOS_OBJ_ID) *const args)
572
{
573
    return KOS_BOOL(KOS_is_infinity(args[0]));
23✔
574
}
575

576
/* @item math is_nan()
577
 *
578
 *     is_nan(number)
579
 *
580
 * Returns `true` if the `number` is a float and its value is a "not-a-number",
581
 * otherwise returns `false`.
582
 *
583
 * Examples:
584
 *
585
 *     > math.is_nan(math.nan)
586
 *     true
587
 *     > math.is_nan(1.0)
588
 *     false
589
 *     > math.is_nan([])
590
 *     false
591
 */
592
static KOS_OBJ_ID kos_is_nan(const KOS_CONTEXT             ctx,
38✔
593
                             const KOS_OBJ_ID              this_obj,
594
                             const uint32_t                num_args,
595
                             KOS_ATOMIC(KOS_OBJ_ID) *const args)
596
{
597
    return KOS_BOOL(KOS_is_nan(args[0]));
38✔
598
}
599

600
/* @item math pow()
601
 *
602
 *     pow(number, power)
603
 *
604
 * Returns `number` raised to `power`.
605
 *
606
 * The returned value is always a float.
607
 *
608
 * Throws an exception if `num` is negative and `power` is not an
609
 * integer value (it can still be a float type, but its value must be
610
 * mathematically an integer).
611
 *
612
 * Examples:
613
 *
614
 *     > math.pow(2, 2)
615
 *     4.0
616
 *     > math.pow(10, -2)
617
 *     0.01
618
 */
619
static KOS_OBJ_ID kos_pow(const KOS_CONTEXT             ctx,
34✔
620
                          const KOS_OBJ_ID              this_obj,
621
                          const uint32_t                num_args,
622
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
623
{
624
    KOS_NUMERIC arg1;
625
    KOS_NUMERIC arg2;
626
    KOS_OBJ_ID  ret   = KOS_BADPTR;
34✔
627
    double      val1;
628
    double      val2;
629
    int         error = KOS_SUCCESS;
34✔
630

631
    arg1 = KOS_get_numeric(args[0]);
34✔
632
    arg2 = KOS_get_numeric(args[1]);
34✔
633

634
    if (arg1.type == KOS_INTEGER_VALUE)
34✔
635
        val1 = (double)arg1.u.i;
21✔
636
    else if (arg1.type == KOS_FLOAT_VALUE)
13✔
637
        val1 = arg1.u.d;
10✔
638
    else
639
        RAISE_EXCEPTION_STR(str_err_not_number);
3✔
640

641
    if (arg2.type == KOS_INTEGER_VALUE)
31✔
642
        val2 = (double)arg2.u.i;
13✔
643
    else if (arg2.type == KOS_FLOAT_VALUE)
18✔
644
        val2 = arg2.u.d;
15✔
645
    else
646
        RAISE_EXCEPTION_STR(str_err_not_number);
3✔
647

648
    if (val1 == 0) {
28✔
649
        if (val2 == 0)
7✔
650
            ret = TO_SMALL_INT(1);
1✔
651
        else if (val2 > 0)
6✔
652
            ret = TO_SMALL_INT(0);
2✔
653
        else
654
            RAISE_EXCEPTION_STR(str_err_pow_0_minus);
4✔
655
    }
656
    else if (val1 == 1 || val2 == 0)
21✔
657
        ret = TO_SMALL_INT(1);
11✔
658
    else if (val1 < 0 && ceil(val2) != val2)
10✔
659
        RAISE_EXCEPTION(str_err_negative_root);
1✔
660
    else
661
        ret = KOS_new_float(ctx, pow(val1, val2));
9✔
662

663
cleanup:
34✔
664
    return error ? KOS_BADPTR : ret;
34✔
665
}
666

667
/* @item math sin()
668
 *
669
 *     sin(number)
670
 *
671
 * Returns sine of `number`.
672
 *
673
 * The returned value is always a float.
674
 *
675
 * Example:
676
 *
677
 *     > math.sin(math.pi / 2)
678
 *     1.0
679
 */
680
static KOS_OBJ_ID kos_sin(const KOS_CONTEXT             ctx,
8✔
681
                          const KOS_OBJ_ID              this_obj,
682
                          const uint32_t                num_args,
683
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
684

685
{
686
    KOS_NUMERIC numeric;
687
    KOS_OBJ_ID  ret   = KOS_BADPTR;
8✔
688
    double      value;
689
    int         error = KOS_SUCCESS;
8✔
690

691
    numeric = KOS_get_numeric(args[0]);
8✔
692

693
    if (numeric.type == KOS_INTEGER_VALUE)
8✔
694
        value = (double)numeric.u.i;
1✔
695
    else if (numeric.type == KOS_FLOAT_VALUE)
7✔
696
        value = numeric.u.d;
7✔
697
    else
UNCOV
698
        RAISE_EXCEPTION_STR(str_err_not_number);
×
699

700
    ret = KOS_new_float(ctx, sin(value));
8✔
701

702
cleanup:
8✔
703
    return error ? KOS_BADPTR : ret;
8✔
704
}
705

706
/* @item math sqrt()
707
 *
708
 *     sqrt(number)
709
 *
710
 * Returns square root of `number`.
711
 *
712
 * The returned value is always a float.
713
 *
714
 * Throws an exception if `number` is negative.
715
 *
716
 * Example:
717
 *
718
 *     > math.sqrt(4)
719
 *     2.0
720
 */
721
static KOS_OBJ_ID kos_sqrt(const KOS_CONTEXT             ctx,
8✔
722
                           const KOS_OBJ_ID              this_obj,
723
                           const uint32_t                num_args,
724
                           KOS_ATOMIC(KOS_OBJ_ID) *const args)
725
{
726
    KOS_NUMERIC numeric;
727
    KOS_OBJ_ID  ret   = KOS_BADPTR;
8✔
728
    double      value;
729
    int         error = KOS_SUCCESS;
8✔
730

731

732
    numeric = KOS_get_numeric(args[0]);
8✔
733

734
    if (numeric.type == KOS_INTEGER_VALUE) {
8✔
735
        if (numeric.u.i < 0)
3✔
736
            RAISE_EXCEPTION(str_err_negative_root);
1✔
737
        value = (double)numeric.u.i;
2✔
738
    }
739
    else if (numeric.type == KOS_FLOAT_VALUE) {
5✔
740
        value = numeric.u.d;
4✔
741
        if (value < 0)
4✔
742
            RAISE_EXCEPTION(str_err_negative_root);
1✔
743
    }
744
    else
745
        RAISE_EXCEPTION_STR(str_err_not_number);
1✔
746

747
    ret = KOS_new_float(ctx, sqrt(value));
5✔
748

749
cleanup:
8✔
750
    return error ? KOS_BADPTR : ret;
8✔
751
}
752

753
/* @item math tan()
754
 *
755
 *     tan(number)
756
 *
757
 * Returns tangent of `number`.
758
 *
759
 * The returned value is always a float.
760
 *
761
 * Example:
762
 *
763
 *     > math.tan(math.pi / 4)
764
 *     1.0
765
 */
766
static KOS_OBJ_ID kos_tan(const KOS_CONTEXT             ctx,
5✔
767
                          const KOS_OBJ_ID              this_obj,
768
                          const uint32_t                num_args,
769
                          KOS_ATOMIC(KOS_OBJ_ID) *const args)
770
{
771
    KOS_NUMERIC numeric;
772
    KOS_OBJ_ID  ret   = KOS_BADPTR;
5✔
773
    double      value;
774
    int         error = KOS_SUCCESS;
5✔
775

776
    numeric = KOS_get_numeric(args[0]);
5✔
777

778
    if (numeric.type == KOS_INTEGER_VALUE)
5✔
779
        value = (double)numeric.u.i;
1✔
780
    else if (numeric.type == KOS_FLOAT_VALUE)
4✔
781
        value = numeric.u.d;
4✔
782
    else
UNCOV
783
        RAISE_EXCEPTION_STR(str_err_not_number);
×
784

785
    ret = KOS_new_float(ctx, tan(value));
5✔
786

787
cleanup:
5✔
788
    return error ? KOS_BADPTR : ret;
5✔
789
}
790

791
KOS_DECLARE_STATIC_CONST_STRING(str_number, "number");
792

793
static const KOS_CONVERT number_arg[2] = {
794
    KOS_DEFINE_MANDATORY_ARG(str_number),
795
    KOS_DEFINE_TAIL_ARG()
796
};
797

798
KOS_DECLARE_STATIC_CONST_STRING(str_power, "power");
799

800
static const KOS_CONVERT pow_args[3] = {
801
    KOS_DEFINE_MANDATORY_ARG(str_number),
802
    KOS_DEFINE_MANDATORY_ARG(str_power ),
803
    KOS_DEFINE_TAIL_ARG()
804
};
805

806
KOS_INIT_MODULE(math, KOS_MODULE_NEEDS_KOS_SOURCE)(KOS_CONTEXT ctx, KOS_OBJ_ID module_obj)
2,530✔
807
{
808
    int       error = KOS_SUCCESS;
1,257✔
809
    KOS_LOCAL module;
810

811
    KOS_init_debug_output();
812

813
    KOS_init_local_with(ctx, &module, module_obj);
1,257✔
814

815
    /* @item math infinity
816
     *
817
     *     infinity
818
     *
819
     * Constant float value representing positive infinity.
820
     */
821
    {
822
        KOS_NUMERIC_VALUE value;
823
        KOS_OBJ_ID        value_obj;
824

825
        value.i = (uint64_t)0x7FF00000U << 32;
1,257✔
826

827
        value_obj = KOS_new_float(ctx, value.d);
1,257✔
828
        TRY_OBJID(value_obj);
1,261✔
829

830
        TRY_ADD_GLOBAL(ctx, module.o, "infinity", value_obj);
1,256✔
831
    }
832

833
    /* @item math nan
834
     *
835
     *     nan
836
     *
837
     * Constant float value representing "not-a-number".
838
     */
839
    {
840
        KOS_NUMERIC_VALUE value;
841
        KOS_OBJ_ID        value_obj;
842

843
        value.i = ((uint64_t)0x7FF00000U << 32) | 1U;
1,252✔
844

845
        value_obj = KOS_new_float(ctx, value.d);
1,252✔
846
        TRY_OBJID(value_obj);
1,255✔
847

848
        TRY_ADD_GLOBAL(ctx, module.o, "nan", value_obj);
1,251✔
849
    }
850

851
    TRY_ADD_FUNCTION(ctx, module.o, "abs",         kos_abs,         number_arg);
1,248✔
852
    TRY_ADD_FUNCTION(ctx, module.o, "acos",        kos_acos,        number_arg);
1,242✔
853
    TRY_ADD_FUNCTION(ctx, module.o, "asin",        kos_asin,        number_arg);
1,239✔
854
    TRY_ADD_FUNCTION(ctx, module.o, "atan",        kos_atan,        number_arg);
1,234✔
855
    TRY_ADD_FUNCTION(ctx, module.o, "ceil",        kos_ceil,        number_arg);
1,225✔
856
    TRY_ADD_FUNCTION(ctx, module.o, "cos",         kos_cos,         number_arg);
1,222✔
857
    TRY_ADD_FUNCTION(ctx, module.o, "exp",         kos_exp,         number_arg);
1,217✔
858
    TRY_ADD_FUNCTION(ctx, module.o, "expm1",       kos_expm1,       number_arg);
1,212✔
859
    TRY_ADD_FUNCTION(ctx, module.o, "floor",       kos_floor,       number_arg);
1,207✔
860
    TRY_ADD_FUNCTION(ctx, module.o, "log",         kos_log,         number_arg);
1,202✔
861
    TRY_ADD_FUNCTION(ctx, module.o, "log10",       kos_log10,       number_arg);
1,197✔
862
    TRY_ADD_FUNCTION(ctx, module.o, "log1p",       kos_log1p,       number_arg);
1,192✔
863
    TRY_ADD_FUNCTION(ctx, module.o, "is_infinity", kos_is_infinity, number_arg);
1,184✔
864
    TRY_ADD_FUNCTION(ctx, module.o, "is_nan",      kos_is_nan,      number_arg);
1,177✔
865
    TRY_ADD_FUNCTION(ctx, module.o, "pow",         kos_pow,         pow_args);
1,174✔
866
    TRY_ADD_FUNCTION(ctx, module.o, "sin",         kos_sin,         number_arg);
1,169✔
867
    TRY_ADD_FUNCTION(ctx, module.o, "sqrt",        kos_sqrt,        number_arg);
1,164✔
868
    TRY_ADD_FUNCTION(ctx, module.o, "tan",         kos_tan,         number_arg);
1,159✔
869

870
cleanup:
1,154✔
871
    KOS_destroy_top_local(ctx, &module);
1,257✔
872

873
    return error;
1,257✔
874
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc