~aritra1911/prime

062f7ec836590d468ea2cdfd6a1db58a9308564f — Aritra Sarkar 2 years ago 5d336d1
Ditch custom `sig128_t` type in favour of `__int128`
2 files changed, 20 insertions(+), 34 deletions(-)

M sha_consts/sha_consts.c
M sha_consts/sha_consts.h
M sha_consts/sha_consts.c => sha_consts/sha_consts.c +20 -27
@@ 124,8 124,8 @@ void frac64(const unsigned long int *primes, int n)

    mpfr_t prime, cbrt_prime;

    /* We assume 113 bits of precision according to IEEE-754 Quadruple precision
     * binary 128 bit floating point numbers */
    /* We assume 113 bits of precision according to IEEE-754 Quadruple
     * precision binary 128 bit floating point numbers */
    mpfr_prec_t prec = 113;

    mpfr_inits2(prec, prime, cbrt_prime, (mpfr_ptr) 0);


@@ 137,34 137,27 @@ void frac64(const unsigned long int *primes, int n)
        /* MPFR's cube root function */
        mpfr_cbrt(cbrt_prime, prime, MPFR_RNDN);

        /* This is an attempt to get raw significand bytes out of MPFR */
        /*
         * This is an attempt to get raw significand bytes out of MPFR
         */

        /* The `mpfr_custom_get_significand()` function returns a pointer to
         * the significand in memory. We shall cast this into a custom type
         * which is able to handle 128 bits of data and we can then access its
         * higher order bits and lower order bits and extract the fractional
         * part accordingly. */
        sig128_t significand = *(sig128_t *)
                               mpfr_custom_get_significand(cbrt_prime);
        /* The  `mpfr_custom_get_significand()`  function   returns  a
         * pointer to the  significand in memory which in this case is
         * 128  bits  wide.  I don't know  how  good  the support  for
         * `__int128` is,  but at least  GCC and clang  are  happy  to
         * compile this for x86_64  with GCC slightly bitching because
         * of  `-Wpedantic`  which is fixed by prefixing the type with
         * `__extension__`.  Hence I'm  ditching  the idea of  using a
         * special struct and figuring out the endianness BS and using
         * `__int128`. Let's see what breaks!
         */
        __extension__ unsigned __int128 significand = *(unsigned __int128 *)
            mpfr_custom_get_significand(cbrt_prime);
        int exponent = mpfr_custom_get_exp(cbrt_prime);

        /* Due to MPFR preserving endianess throughout the length of the
         * significand, the upper and lower 64-bit words need to be swapped in
         * case the machine is little endian.
         *
         * Here we deternine the endianess in a quick and dirty way: */
        int end_check = 1;
        if ( *(uint8_t *) &end_check ) {
            /* We detect little endian system */
            uint64_t temp = significand.upper;
            significand.upper = significand.lower;
            significand.lower = temp;
        }

        /* Then shift the entire 128 bit word left by the exponent */
        uint64_t fractional_part = significand.upper << exponent
                                   |
                                   significand.lower >> (64 - exponent);
        /* Shift the entire 128 bit word left by the exponent and then
         * take the most significand 64 bits. */
        uint64_t fractional_part = significand >> (64 - exponent);

        printf("0x%016"PRIx64"\n", fractional_part);
    }

M sha_consts/sha_consts.h => sha_consts/sha_consts.h +0 -7
@@ 1,13 1,6 @@
#ifndef _SHA_CONSTS_H
# define _SHA_CONSTS_H

# include <stdint.h>

typedef struct {
    uint64_t upper;
    uint64_t lower;
} sig128_t;

void frac32(const unsigned long int *, int);
void frac64(const unsigned long int *, int);