flint-sys 0.9.0

Bindings to the FLINT C library
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/*
    Copyright (C) 2024 Fredrik Johansson

    This file is part of FLINT.

    FLINT is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.  See <https://www.gnu.org/licenses/>.
*/

#ifndef NFLOAT_H
#define NFLOAT_H

#ifdef NFLOAT_INLINES_C
#define NFLOAT_INLINE
#else
#define NFLOAT_INLINE static inline
#endif

#include "mpn_extras.h"
#include "gr_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* The upper limit is so that temporary buffers are safe to allocate on
   the stack and so that simple operations like swapping are not too
   expensive compared to a pointer-and-size representation. */
#if FLINT_BITS == 64
#define NFLOAT_MIN_LIMBS 1
#define NFLOAT_MAX_LIMBS 66
#else
#define NFLOAT_MIN_LIMBS 1
#define NFLOAT_MAX_LIMBS 132
#endif

/* Number of header limbs used to encode sign + exponent. We use a
   whole limb for the sign bit to avoid the overhead of bit fiddling. */
#define NFLOAT_HEADER_LIMBS 2
#define NFLOAT_EXP(x) (((slong *) x)[0])
#define NFLOAT_SGNBIT(x) (((nn_ptr) x)[1])
#define NFLOAT_D(x) (((nn_ptr) x) + NFLOAT_HEADER_LIMBS)
#define NFLOAT_DATA(x) (((nn_ptr) x))

/* Limbs needed to hold a temporary element of any precision. */
#define NFLOAT_MAX_ALLOC (NFLOAT_HEADER_LIMBS + NFLOAT_MAX_LIMBS)

/* The exponent limits should not be too close to the word boundary,
   so that we can add two exponents plus some adjustmenets
   and safely intercept overflow/underflow. */
#define NFLOAT_MIN_EXP (WORD_MIN / 4)
#define NFLOAT_MAX_EXP (WORD_MAX / 4)

/* Special values (including zero). */
/* TODO: is it better to encode special values in the exponent or in
         the sign field? */
/* TODO: do we want signed zero (optionally)? */
#define NFLOAT_EXP_ZERO      WORD_MIN
#define NFLOAT_EXP_POS_INF   (WORD_MIN+1)
#define NFLOAT_EXP_NEG_INF   (WORD_MIN+2)
#define NFLOAT_EXP_NAN       (WORD_MIN+3)
#define NFLOAT_IS_SPECIAL(x) (NFLOAT_EXP(x) < NFLOAT_MIN_EXP)
#define NFLOAT_IS_ZERO(x)    (NFLOAT_EXP(x) == NFLOAT_EXP_ZERO)
#define NFLOAT_IS_POS_INF(x) (NFLOAT_EXP(x) == NFLOAT_EXP_POS_INF)
#define NFLOAT_IS_NEG_INF(x) (NFLOAT_EXP(x) == NFLOAT_EXP_NEG_INF)
#define NFLOAT_IS_INF(x)     (NFLOAT_IS_POS_INF(x) || NFLOAT_IS_NEG_INF(x))
#define NFLOAT_IS_NAN(x)     (NFLOAT_EXP(x) == NFLOAT_EXP_NAN)

/* Context flags to indicate whether we want to allow special values
   or return GR_DOMAIN / GR_UNABLE. */
#define NFLOAT_ALLOW_UNDERFLOW 1
#define NFLOAT_ALLOW_INF       2
#define NFLOAT_ALLOW_NAN       4
/* Context flags for directed rounding (experimental) */
#define NFLOAT_RND_FLOOR       8
#define NFLOAT_RND_CEIL        16

typedef struct
{
    slong nlimbs;
    int flags;
    int rnd;    /* Allow rounding modes? Currently unused. */
}
_nfloat_ctx_struct;

typedef void * nfloat_ptr;
typedef const void * nfloat_srcptr;

#define NFLOAT_CTX(ctx) ((_nfloat_ctx_struct *)(ctx))
#define NFLOAT_CTX_NLIMBS(ctx) (NFLOAT_CTX(ctx)->nlimbs)
#define NFLOAT_CTX_PREC(ctx) ((NFLOAT_CTX(ctx)->nlimbs) * FLINT_BITS)
#define NFLOAT_CTX_FLAGS(ctx) (NFLOAT_CTX(ctx)->flags)
#define NFLOAT_CTX_RND(ctx) (NFLOAT_CTX(ctx)->rnd)
#define NFLOAT_CTX_DATA_NLIMBS(ctx) (NFLOAT_CTX_NLIMBS(ctx) + NFLOAT_HEADER_LIMBS)
#define NFLOAT_CTX_HAS_INF_NAN(ctx) ((NFLOAT_CTX_FLAGS(ctx) & (NFLOAT_ALLOW_INF | NFLOAT_ALLOW_NAN)) != 0)
#define NFLOAT_CTX_HAS_DIRECTED_ROUNDING(ctx) ((NFLOAT_CTX_FLAGS(ctx) & (NFLOAT_RND_FLOOR | NFLOAT_RND_CEIL)) != 0)

typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[64 / FLINT_BITS]; } nfloat64_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[128 / FLINT_BITS]; } nfloat128_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[192 / FLINT_BITS]; } nfloat192_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[256 / FLINT_BITS]; } nfloat256_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[384 / FLINT_BITS]; } nfloat384_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[512 / FLINT_BITS]; } nfloat512_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[1024 / FLINT_BITS]; } nfloat1024_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[2048 / FLINT_BITS]; } nfloat2048_struct;
typedef struct { ulong head[NFLOAT_HEADER_LIMBS]; ulong d[4096 / FLINT_BITS]; } nfloat4096_struct;

typedef nfloat64_struct nfloat64_t[1];
typedef nfloat128_struct nfloat128_t[1];
typedef nfloat192_struct nfloat192_t[1];
typedef nfloat256_struct nfloat256_t[1];
typedef nfloat384_struct nfloat384_t[1];
typedef nfloat512_struct nfloat512_t[1];
typedef nfloat1024_struct nfloat1024_t[1];
typedef nfloat2048_struct nfloat2048_t[1];
typedef nfloat4096_struct nfloat4096_t[1];

#define LIMB_MSB_IS_SET(n) ((slong) (n) < 0)

int nfloat_ctx_init(gr_ctx_t ctx, slong prec, int flags);
int nfloat_ctx_write(gr_stream_t out, gr_ctx_t ctx);

NFLOAT_INLINE void
nfloat_init(nfloat_ptr res, gr_ctx_t ctx)
{
    NFLOAT_EXP(res) = NFLOAT_EXP_ZERO;
    NFLOAT_SGNBIT(res) = 0;
}

NFLOAT_INLINE void
nfloat_clear(nfloat_ptr res, gr_ctx_t ctx)
{
    FLINT_ASSERT(NFLOAT_IS_SPECIAL(res) || LIMB_MSB_IS_SET(NFLOAT_D(res)[NFLOAT_CTX_NLIMBS(ctx)-1]));
}

void nfloat_swap(nfloat_ptr x, nfloat_ptr y, gr_ctx_t ctx);
int nfloat_set(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

truth_t nfloat_equal(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);

NFLOAT_INLINE
int nfloat_ctx_set_real_prec(gr_ctx_t ctx, slong prec)
{
    return GR_UNABLE;
}

NFLOAT_INLINE
int nfloat_ctx_get_real_prec(slong * res, gr_ctx_t ctx)
{
    *res = NFLOAT_CTX_PREC(ctx);
    return GR_SUCCESS;
}

NFLOAT_INLINE int
nfloat_zero(nfloat_ptr res, gr_ctx_t ctx)
{
    NFLOAT_EXP(res) = NFLOAT_EXP_ZERO;
    NFLOAT_SGNBIT(res) = 0;
    return GR_SUCCESS;
}

int nfloat_pos_inf(nfloat_ptr res, gr_ctx_t ctx);
int nfloat_neg_inf(nfloat_ptr res, gr_ctx_t ctx);
int nfloat_nan(nfloat_ptr res, gr_ctx_t ctx);

int _nfloat_underflow(nfloat_ptr res, int sgnbit, gr_ctx_t ctx);
int _nfloat_overflow(nfloat_ptr res, int sgnbit, gr_ctx_t ctx);

#define NFLOAT_HANDLE_UNDERFLOW(res, ctx) \
    do { \
        if (FLINT_UNLIKELY(NFLOAT_EXP(res) < NFLOAT_MIN_EXP)) \
            return _nfloat_underflow(res, NFLOAT_SGNBIT(res), ctx); \
    } while (0)

#define NFLOAT_HANDLE_OVERFLOW(res, ctx) \
    do { \
        if (FLINT_UNLIKELY(NFLOAT_EXP(res) < NFLOAT_MIN_EXP)) \
            return _nfloat_underflow(res, NFLOAT_SGNBIT(res), ctx); \
    } while (0)

#define NFLOAT_HANDLE_UNDERFLOW_OVERFLOW(res, ctx) \
    do { \
        NFLOAT_HANDLE_UNDERFLOW(res, ctx); \
        NFLOAT_HANDLE_OVERFLOW(res, ctx); \
    } while (0)

int nfloat_one(nfloat_ptr res, gr_ctx_t ctx);
int nfloat_neg_one(nfloat_ptr res, gr_ctx_t ctx);

NFLOAT_INLINE truth_t
nfloat_is_zero(nfloat_srcptr x, gr_ctx_t ctx)
{
    if (NFLOAT_IS_NAN(x))
        return T_UNKNOWN;

    return NFLOAT_IS_ZERO(x) ? T_TRUE : T_FALSE;
}

truth_t nfloat_is_one(nfloat_srcptr x, gr_ctx_t ctx);
truth_t nfloat_is_neg_one(nfloat_srcptr x, gr_ctx_t ctx);

int nfloat_set_ui(nfloat_ptr res, ulong x, gr_ctx_t ctx);
int nfloat_set_si(nfloat_ptr res, slong x, gr_ctx_t ctx);

/* Here exp is understood such that {x, xn} is a fraction in [0, 1). */
int _nfloat_set_mpn_2exp(nfloat_ptr res, nn_srcptr x, slong xn, slong exp, int xsgnbit, gr_ctx_t ctx);

NFLOAT_INLINE int
nfloat_set_mpn_2exp(nfloat_ptr res, nn_srcptr x, slong xn, slong exp, int xsgnbit, gr_ctx_t ctx)
{
    while (xn != 0 && x[xn - 1] == 0)
    {
        xn--;
        exp -= FLINT_BITS;
    }

    if (xn == 0)
        return nfloat_zero(res, ctx);

    return _nfloat_set_mpn_2exp(res, x, xn, exp, xsgnbit, ctx);
}

NFLOAT_INLINE int
nfloat_1_set_2_2exp(nfloat_ptr res, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)
{
    slong norm;

    if (x1 == 0)
    {
        if (x0 == 0)
            return nfloat_zero(res, ctx);

        norm = flint_clz(x0);
        NFLOAT_EXP(res) = exp - FLINT_BITS - norm;
        NFLOAT_SGNBIT(res) = xsgnbit;
        NFLOAT_D(res)[0] = x0 << norm;
    }
    else if (LIMB_MSB_IS_SET(x1))
    {
        NFLOAT_EXP(res) = exp;
        NFLOAT_SGNBIT(res) = xsgnbit;
        NFLOAT_D(res)[0] = x1;
    }
    else
    {
        norm = flint_clz(x1);
        NFLOAT_EXP(res) = exp - norm;
        NFLOAT_SGNBIT(res) = xsgnbit;
        NFLOAT_D(res)[0] = (x1 << norm) | (x0 >> (FLINT_BITS - norm));
    }

    NFLOAT_HANDLE_UNDERFLOW_OVERFLOW(res, ctx);
    return GR_SUCCESS;
}

NFLOAT_INLINE int
nfloat_1_set_3_2exp(nfloat_ptr res, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)
{
    if (x2 == 0)
        return nfloat_1_set_2_2exp(res, x1, x0, exp - FLINT_BITS, xsgnbit, ctx);
    else
        return nfloat_1_set_2_2exp(res, x2, x1, exp, xsgnbit, ctx);
}

NFLOAT_INLINE int
nfloat_2_set_3_2exp(nfloat_ptr res, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)
{
    slong norm;

    if (x2 == 0)
    {
        if (x1 == 0)
        {
            if (x0 == 0)
                return nfloat_zero(res, ctx);

            norm = flint_clz(x0);
            exp = exp - 2 * FLINT_BITS - norm;
            x1 = 0;
            x2 = x0 << norm;
        }
        else if (LIMB_MSB_IS_SET(x1))
        {
            exp = exp - FLINT_BITS;
            x2 = x1;
            x1 = x0;
        }
        else
        {
            norm = flint_clz(x1);
            exp = exp - FLINT_BITS - norm;
            x2 = (x1 << norm) | (x0 >> (FLINT_BITS - norm));
            x1 = (x0 << norm);
        }
    }
    else if (!LIMB_MSB_IS_SET(x2))
    {
        norm = flint_clz(x2);
        exp = exp - norm;
        x2 = (x2 << norm) | (x1 >> (FLINT_BITS - norm));
        x1 = (x1 << norm) | (x0 >> (FLINT_BITS - norm));
    }

    NFLOAT_EXP(res) = exp;
    NFLOAT_SGNBIT(res) = xsgnbit;
    NFLOAT_D(res)[0] = x1;
    NFLOAT_D(res)[1] = x2;
    NFLOAT_HANDLE_UNDERFLOW_OVERFLOW(res, ctx);
    return GR_SUCCESS;
}

NFLOAT_INLINE int
nfloat_2_set_4_2exp(nfloat_ptr res, ulong x3, ulong x2, ulong x1, ulong x0, slong exp, int xsgnbit, gr_ctx_t ctx)
{
    if (x3 == 0)
        return nfloat_2_set_3_2exp(res, x2, x1, x0, exp - FLINT_BITS, xsgnbit, ctx);
    else
        return nfloat_2_set_3_2exp(res, x3, x2, x1, exp, xsgnbit, ctx);
}



int nfloat_set_fmpz(nfloat_ptr res, const fmpz_t x, gr_ctx_t ctx);

#ifdef ARF_H
int nfloat_set_arf(nfloat_ptr res, const arf_t x, gr_ctx_t ctx);
int nfloat_get_arf(arf_t res, nfloat_srcptr x, gr_ctx_t ctx);
#endif

int nfloat_get_d_2exp_si(double * mant, slong * expo, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_get_fmpz(fmpz_t res, nfloat_srcptr x, gr_ctx_t ctx);

int nfloat_set_fmpq(nfloat_ptr res, const fmpq_t v, gr_ctx_t ctx);
int nfloat_set_d(nfloat_ptr res, double x, gr_ctx_t ctx);
int nfloat_set_str(nfloat_ptr res, const char * x, gr_ctx_t ctx);
int nfloat_set_other(nfloat_ptr res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx);

int nfloat_write(gr_stream_t out, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_randtest(nfloat_ptr res, flint_rand_t state, gr_ctx_t ctx);

int nfloat_neg(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_abs(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int _nfloat_cmp(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int _nfloat_cmpabs(nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_cmp(int * res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_cmpabs(int * res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_sgn(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_im(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

int _nfloat_add_1(nfloat_ptr res, ulong x0, slong xexp, int xsgnbit, ulong y0, slong delta, gr_ctx_t ctx);
int _nfloat_sub_1(nfloat_ptr res, ulong x0, slong xexp, int xsgnbit, ulong y0, slong delta, gr_ctx_t ctx);
int _nfloat_add_2(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, gr_ctx_t ctx);
int _nfloat_sub_2(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, gr_ctx_t ctx);
int _nfloat_add_3(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx);
int _nfloat_sub_3(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx);
int _nfloat_add_4(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx);
int _nfloat_sub_4(nfloat_ptr res, nn_srcptr x, slong xexp, int xsgnbit, nn_srcptr y, slong delta, gr_ctx_t ctx);
int _nfloat_add_n(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, slong nlimbs, gr_ctx_t ctx);
int _nfloat_sub_n(nfloat_ptr res, nn_srcptr xd, slong xexp, int xsgnbit, nn_srcptr yd, slong delta, slong nlimbs, gr_ctx_t ctx);

int nfloat_add(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_sub(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_mul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_addmul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_submul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_sqr(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

int nfloat_mul_2exp_si(nfloat_ptr res, nfloat_srcptr x, slong y, gr_ctx_t ctx);

int nfloat_inv(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_div(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_div_ui(nfloat_ptr res, nfloat_srcptr x, ulong y, gr_ctx_t ctx);
int nfloat_div_si(nfloat_ptr res, nfloat_srcptr x, slong y, gr_ctx_t ctx);

int nfloat_sqrt(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_rsqrt(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

int nfloat_floor(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_ceil(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_trunc(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_nint(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

int nfloat_pi(nfloat_ptr res, gr_ctx_t ctx);
int nfloat_pow(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, gr_ctx_t ctx);
int nfloat_exp(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_expm1(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_log(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_log1p(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_sin(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_cos(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_tan(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_sinh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_cosh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_tanh(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_atan(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_gamma(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);
int nfloat_zeta(nfloat_ptr res, nfloat_srcptr x, gr_ctx_t ctx);

void _nfloat_vec_init(nfloat_ptr res, slong len, gr_ctx_t ctx);
void _nfloat_vec_clear(nfloat_ptr res, slong len, gr_ctx_t ctx);
int _nfloat_vec_set(nfloat_ptr res, nfloat_srcptr x, slong len, gr_ctx_t ctx);
int _nfloat_vec_zero(nfloat_ptr res, slong len, gr_ctx_t ctx);

int _nfloat_vec_add(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_vec_sub(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_vec_mul(nfloat_ptr res, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_vec_mul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx);
int _nfloat_vec_addmul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx);
int _nfloat_vec_submul_scalar(nfloat_ptr res, nfloat_srcptr x, slong len, nfloat_srcptr y, gr_ctx_t ctx);

int _nfloat_vec_dot(nfloat_ptr res, nfloat_srcptr initial, int subtract, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_vec_dot_rev(nfloat_ptr res, nfloat_srcptr initial, int subtract, nfloat_srcptr x, nfloat_srcptr y, slong len, gr_ctx_t ctx);

int nfloat_mat_mul_fixed(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong max_extra_prec, gr_ctx_t ctx);
int nfloat_mat_mul_block(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong min_block_size, gr_ctx_t ctx);
int nfloat_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx);

int nfloat_mat_nonsingular_solve_tril(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx);
int nfloat_mat_nonsingular_solve_triu(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx);
int nfloat_mat_lu(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx);
int nfloat_mat_lq(gr_mat_t L, gr_mat_t Q, const gr_mat_t A, gr_ctx_t ctx);

/* Complex numbers */
/* Note: we use the same context data for real and complex rings
   (only which_ring and sizeof_elem differ). This allows us to call
   nfloat methods on the real and imaginary parts without creating
   a temporary nfloat context object, as long as the nfloat methods
   don't call any generic gr methods internally.
*/

typedef nfloat_ptr nfloat_complex_ptr;
typedef nfloat_srcptr nfloat_complex_srcptr;

int nfloat_complex_ctx_init(gr_ctx_t ctx, slong prec, int flags);

#define NFLOAT_COMPLEX_CTX_DATA_NLIMBS(ctx) (2 * NFLOAT_CTX_DATA_NLIMBS(ctx))

#define NFLOAT_COMPLEX_RE(ptr, ctx) (ptr)
#define NFLOAT_COMPLEX_IM(ptr, ctx) ((nn_ptr) (ptr) + NFLOAT_CTX_DATA_NLIMBS(ctx))

#define NFLOAT_COMPLEX_IS_SPECIAL(x, ctx) (NFLOAT_IS_SPECIAL(NFLOAT_COMPLEX_RE(x, ctx)) || NFLOAT_IS_SPECIAL(NFLOAT_COMPLEX_IM(x, ctx)))
#define NFLOAT_COMPLEX_IS_ZERO(x, ctx) (NFLOAT_IS_ZERO(NFLOAT_COMPLEX_RE(x, ctx)) && NFLOAT_IS_ZERO(NFLOAT_COMPLEX_IM(x, ctx)))


NFLOAT_INLINE void
nfloat_complex_init(nfloat_complex_ptr res, gr_ctx_t ctx)
{
    nfloat_init(NFLOAT_COMPLEX_RE(res, ctx), ctx);
    nfloat_init(NFLOAT_COMPLEX_IM(res, ctx), ctx);
}

NFLOAT_INLINE void
nfloat_complex_clear(nfloat_complex_ptr res, gr_ctx_t ctx)
{
    FLINT_ASSERT(NFLOAT_IS_SPECIAL(NFLOAT_COMPLEX_RE(res, ctx)) || LIMB_MSB_IS_SET(NFLOAT_D(NFLOAT_COMPLEX_RE(res, ctx))[NFLOAT_CTX_NLIMBS(ctx)-1]));
    FLINT_ASSERT(NFLOAT_IS_SPECIAL(NFLOAT_COMPLEX_IM(res, ctx)) || LIMB_MSB_IS_SET(NFLOAT_D(NFLOAT_COMPLEX_IM(res, ctx))[NFLOAT_CTX_NLIMBS(ctx)-1]));
}

NFLOAT_INLINE int
nfloat_complex_zero(nfloat_complex_ptr res, gr_ctx_t ctx)
{
    nfloat_zero(NFLOAT_COMPLEX_RE(res, ctx), ctx);
    nfloat_zero(NFLOAT_COMPLEX_IM(res, ctx), ctx);
    return GR_SUCCESS;
}

#ifdef ACF_H
int nfloat_complex_get_acf(acf_t res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_set_acf(nfloat_complex_ptr res, const acf_t x, gr_ctx_t ctx);
#endif

#ifdef ACB_H
int nfloat_complex_get_acb(acb_t res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_set_acb(nfloat_complex_ptr res, const acb_t x, gr_ctx_t ctx);
#endif

int nfloat_complex_write(gr_stream_t out, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_randtest(nfloat_complex_ptr res, flint_rand_t state, gr_ctx_t ctx);

void nfloat_complex_swap(nfloat_complex_ptr x, nfloat_complex_ptr y, gr_ctx_t ctx);
int nfloat_complex_set(nfloat_complex_ptr res, nfloat_complex_ptr x, gr_ctx_t ctx);
int nfloat_complex_one(nfloat_complex_ptr res, gr_ctx_t ctx);
int nfloat_complex_neg_one(nfloat_complex_ptr res, gr_ctx_t ctx);
truth_t nfloat_complex_is_zero(nfloat_complex_srcptr x, gr_ctx_t ctx);
truth_t nfloat_complex_is_one(nfloat_complex_srcptr x, gr_ctx_t ctx);
truth_t nfloat_complex_is_neg_one(nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_i(nfloat_complex_ptr res, gr_ctx_t ctx);
int nfloat_complex_pi(nfloat_complex_ptr res, gr_ctx_t ctx);
int nfloat_complex_conj(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_re(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_im(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
truth_t nfloat_complex_equal(nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_set_si(nfloat_complex_ptr res, slong x, gr_ctx_t ctx);
int nfloat_complex_set_ui(nfloat_complex_ptr res, ulong x, gr_ctx_t ctx);
int nfloat_complex_set_fmpz(nfloat_complex_ptr res, const fmpz_t x, gr_ctx_t ctx);
int nfloat_complex_set_fmpq(nfloat_complex_ptr res, const fmpq_t x, gr_ctx_t ctx);
int nfloat_complex_set_d(nfloat_complex_ptr res, double x, gr_ctx_t ctx);
int nfloat_complex_set_other(nfloat_complex_ptr res, gr_srcptr x, gr_ctx_t x_ctx, gr_ctx_t ctx);
int nfloat_complex_neg(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_add(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_sub(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int _nfloat_complex_sqr_naive(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx);
int _nfloat_complex_sqr_standard(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx);
int _nfloat_complex_sqr_karatsuba(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx);
int _nfloat_complex_sqr(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, gr_ctx_t ctx);
int nfloat_complex_sqr(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int _nfloat_complex_mul_naive(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx);
int _nfloat_complex_mul_standard(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx);
int _nfloat_complex_mul_karatsuba(nfloat_ptr res1, nfloat_ptr res2, nfloat_srcptr a, nfloat_srcptr b, nfloat_srcptr c, nfloat_srcptr d, gr_ctx_t ctx);
int nfloat_complex_mul(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_inv(nfloat_complex_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);
int nfloat_complex_div(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_mul_2exp_si(nfloat_complex_ptr res, nfloat_complex_srcptr x, slong y, gr_ctx_t ctx);
int nfloat_complex_cmp(int * res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_cmpabs(int * res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, gr_ctx_t ctx);
int nfloat_complex_abs(nfloat_ptr res, nfloat_complex_srcptr x, gr_ctx_t ctx);

void _nfloat_complex_vec_init(nfloat_complex_ptr res, slong len, gr_ctx_t ctx);
void _nfloat_complex_vec_clear(nfloat_complex_ptr res, slong len, gr_ctx_t ctx);
int _nfloat_complex_vec_zero(nfloat_complex_ptr res, slong len, gr_ctx_t ctx);
int _nfloat_complex_vec_set(nfloat_complex_ptr res, nfloat_complex_srcptr x, slong len, gr_ctx_t ctx);
int _nfloat_complex_vec_add(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_complex_vec_sub(nfloat_complex_ptr res, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx);

int _nfloat_complex_vec_dot(nfloat_complex_ptr res, nfloat_complex_srcptr initial, int subtract, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx);
int _nfloat_complex_vec_dot_rev(nfloat_complex_ptr res, nfloat_complex_srcptr initial, int subtract, nfloat_complex_srcptr x, nfloat_complex_srcptr y, slong len, gr_ctx_t ctx);

int nfloat_complex_mat_mul_fixed(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong max_extra_prec, gr_ctx_t ctx);
int nfloat_complex_mat_mul_block(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, slong min_block_size, gr_ctx_t ctx);
int nfloat_complex_mat_mul_reorder(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx);
int nfloat_complex_mat_mul(gr_mat_t C, const gr_mat_t A, const gr_mat_t B, gr_ctx_t ctx);

int nfloat_complex_mat_nonsingular_solve_tril(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx);
int nfloat_complex_mat_nonsingular_solve_triu(gr_mat_t X, const gr_mat_t L, const gr_mat_t B, int unit, gr_ctx_t ctx);
int nfloat_complex_mat_lu(slong * rank, slong * P, gr_mat_t LU, const gr_mat_t A, int rank_check, gr_ctx_t ctx);

/* Fixed-point arithmetic */

void _nfixed_print(nn_srcptr x, slong nlimbs, slong exp);
void _nfixed_vec_add(nn_ptr res, nn_srcptr a, nn_srcptr b, slong len, slong nlimbs);
void _nfixed_vec_sub(nn_ptr res, nn_srcptr a, nn_srcptr b, slong len, slong nlimbs);

void _nfixed_dot_2(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_3(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_4(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_5(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_6(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_7(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);
void _nfixed_dot_8(nn_ptr res, nn_srcptr x, slong xstride, nn_srcptr y, slong ystride, slong len);

void _nfixed_mat_mul_classical_precise(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs);
void _nfixed_mat_mul_classical(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs);
void _nfixed_mat_mul_waksman(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs);
void _nfixed_mat_mul_strassen(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong cutoff, slong nlimbs);
void _nfixed_mat_mul(nn_ptr C, nn_srcptr A, nn_srcptr B, slong m, slong n, slong p, slong nlimbs);

void _nfixed_mat_mul_bound_classical(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs);
void _nfixed_mat_mul_bound_waksman(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs);
void _nfixed_mat_mul_bound_strassen(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong cutoff, slong nlimbs);
void _nfixed_mat_mul_bound(double * bound, double * error, slong m, slong n, slong p, double A, double B, slong nlimbs);
void _nfixed_complex_mat_mul_bound(double * bound, double * error, slong m, slong n, slong p, double A, double B, double C, double D, slong nlimbs);


#ifdef __cplusplus
}
#endif

#endif