• Convert a base 10 mantissa/exponent to a base 2 mantissa exponent

    From Hans Bezemer@the.beez.speaks@gmail.com to comp.lang.c on Fri Jun 12 21:08:05 2026
    From Newsgroup: comp.lang.c

    Hi!

    The algorithms I've seen on the net require quite some bit hacking to
    get that done. Like: https://kyledewey.github.io/comp122-fall17/lecture/week_2/floating_point_interconversions.html

    I've designed the following algorithm which seems more straight forward.
    Now my question is: is this a reinvention of a known one -- or is this a
    new approach? Note that this works best with a large mantissa -- so I
    provided a word to normalize the mantissa/exponent pair, called
    normalize10().

    Also included: an integer version of pow(). BTW, no idea why it works,
    but it works for sane input values.

    Hans Bezemer

    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <limits.h>

    typedef struct {
    long long mantissa;
    long exponent;
    } me;

    long power (long base, long exp) /* integer version of pow() */
    {
    long long a = 1LL;

    do {
    if (exp & 1) a *= base;
    exp /= 2; base *= base;
    } while (exp != 0);

    return (a);
    }

    /* normalize mantissa/exponent */
    void normalize10 (me* zen, long long mant, long exp)
    { /* save sign of mantissa */
    char msign = (zen -> mantissa) < 0LL;
    /* get absolute value of mantissa */
    zen -> mantissa = llabs (zen -> mantissa);
    /* increase mantissa */
    while ((zen -> mantissa < mant) && (zen -> exponent > exp))
    { /* while between limits */
    zen -> mantissa *= 10; --(zen -> exponent);
    } /* multiply by 10 */
    /* correct mantissa sign if
    required */
    if (msign) zen -> mantissa = -(zen -> mantissa);
    }

    /* convert from radix 10 to
    radix 2 */
    void me10tome2 (me* zen)
    { /* save signs of mantissa and
    exponent */
    char msign = (zen -> mantissa) < 0LL;
    char esign = (zen -> exponent) < 0L;
    long exp2;

    long me10; /* radix 10 multiplication factor */
    long me2; /* radix 2 multiplication factor */

    if (zen -> exponent) { /* if exponent is non-zero */
    zen -> mantissa = llabs (zen -> mantissa);
    zen -> exponent = labs (zen -> exponent);
    /* get absolute value of
    mantissa and exponent */
    exp2 = (((zen -> exponent) * 10) + 2) / 3;
    /* convert exponent to radix 2 */
    me10 = power (10, zen -> exponent);
    me2 = 1 << exp2; /* calculate multiplication
    factors */

    if (esign) { /* if negative exponent */
    zen -> exponent = -exp2;
    zen -> mantissa = (zen -> mantissa * me2) / me10;
    } else { /* if positive exponent */
    zen -> exponent = exp2;
    zen -> mantissa = (zen -> mantissa * me10) / me2;
    }
    /* correct mantissa sign if
    required */
    if (msign) zen -> mantissa = -(zen -> mantissa);
    }
    }


    int main (int argc, char** argv)
    {
    me z = { 1000LL, -4L }; /* 1000E-4 */

    normalize10 (&z, LONG_MAX, -9); /* normalize mantissa and
    exponent */
    me10tome2 (&z); /* convert to radix 2 */
    /* check result */
    printf("Verification:\t%lld * 2^(%ld) = %f\n",
    z.mantissa, z.exponent, z.mantissa * pow(2.0, z.exponent));
    }

    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From ram@ram@zedat.fu-berlin.de (Stefan Ram) to comp.lang.c on Fri Jun 12 19:24:56 2026
    From Newsgroup: comp.lang.c

    Hans Bezemer <the.beez.speaks@gmail.com> wrote or quoted:
    /* increase mantissa */
    while ((zen -> mantissa < mant) && (zen -> exponent > exp))
    { /* while between limits */
    zen -> mantissa *= 10; --(zen -> exponent);
    } /* multiply by 10 */

    Above, you mix pre-comments (referring to what follows) with
    post-comments (referring to what precedes) giving them /exactly
    the same format/, which makes them hard to read.

    I'd prefer something like,

    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <limits.h>

    typedef struct {
    long long mantissa;
    long exponent;
    } me;

    /* integer version of pow() */
    long power (long base, long exp)
    {
    long long a = 1LL;

    do {
    if (exp & 1) a *= base;
    exp /= 2; base *= base;
    } while (exp != 0);

    return a; }

    /* normalize mantissa/exponent */
    void normalize10 (me* zen, long long mant, long exp)
    {
    /* save sign of mantissa */
    char msign = (zen -> mantissa) < 0LL;

    /* get absolute value of mantissa */
    zen -> mantissa = llabs (zen -> mantissa);

    /* increase mantissa */
    while ((zen -> mantissa < mant) && (zen -> exponent > exp))
    { /* while between limits */
    zen -> mantissa *= 10; --(zen -> exponent); /* multiply by 10 */ }

    /* correct mantissa sign if required */
    if (msign) zen -> mantissa = -(zen -> mantissa); }

    /* convert from radix 10 to radix 2 */
    void me10tome2 (me* zen)
    { /* save signs of mantissa and exponent */
    char msign = (zen -> mantissa) < 0LL;
    char esign = (zen -> exponent) < 0L;
    long exp2;

    long me10; /* radix 10 multiplication factor */
    long me2; /* radix 2 multiplication factor */

    if (zen -> exponent) { /* if exponent is non-zero */
    zen -> mantissa = llabs (zen -> mantissa);
    zen -> exponent = labs (zen -> exponent); /* get absolute value of mantissa and exponent */
    exp2 = (((zen -> exponent) * 10) + 2) / 3; /* convert exponent to radix 2 */
    me10 = power (10, zen -> exponent);
    me2 = 1 << exp2; /* calculate multiplication factors */

    if (esign) { /* if negative exponent */
    zen -> exponent = -exp2;
    zen -> mantissa = (zen -> mantissa * me2) / me10;
    } else { /* if positive exponent */
    zen -> exponent = exp2;
    zen -> mantissa = (zen -> mantissa * me10) / me2;
    }

    /* correct mantissa sign if required */
    if (msign) zen -> mantissa = -(zen -> mantissa); }}


    int main (int argc, char** argv)
    {
    me z = { 1000LL, -4L }; /* 1000E-4 */

    normalize10 (&z, LONG_MAX, -9); /* normalize mantissa and exponent */
    me10tome2 (&z); /* convert to radix 2 */

    /* check result */
    printf("Verification:\t%lld * 2^(%ld) = %f\n",
    z.mantissa, z.exponent, z.mantissa * pow(2.0, z.exponent)); }

    . Here's what that former web search-engine said,

    | This algorithm is a variant of a known, standard approach for base
    | conversion in floating-point software libraries rather than a
    | brand-new mathematical discovery.
    |
    | It implements a fixed-precision, scaling-factor conversion method
    | using log approximations.
    |
    | Why It Is a Known Approach
    |
    | The core logic relies on two standard computer science techniques:
    |
    | Logarithmic Scaling Estimation The line exp2 = (((zen -> exponent) *
    | 10) + 2) / 3; approximates log2(10) ~ 3.3333. Multiplying by 10 and
    | dividing by 3 yields 3.3333, which is a classic integer approximation
    | used to guess the required binary exponent size for a given decimal
    | exponent.
    |
    | Exponentiation by Squaring Your power function is the standard,
    | well-known exponentiation-by-squaring algorithm used to compute powers
    | in O(log n) time.
    |
    | Limitations and Risks of This Implementation
    |
    | While the general concept is standard, this specific implementation
    | has severe edge-case flaws that prevent it from being used in
    | production environments:
    |
    | Integer Overflow The power(10, zen->exponent) call will rapidly
    | overflow standard 64-bit integer limits. 10^19 is the absolute maximum
    | a 64-bit unsigned integer can hold. If the input exponent is larger
    | than 18, me10 will overflow and corrupt the calculation.
    |
    | Bit-Shift Overflow The line me2 = 1 << exp2; uses standard integer
    | shifting. In C, shifting a 32-bit signed integer by more than 31 bits
    | (or a 64-bit integer by more than 63 bits) causes undefined behavior
    | and severe overflow.
    |
    | Precision Loss Standard library conversion functions (like strtod or
    | printf internals) use arbitrary-precision arithmetic (bignums) or
    | specialized algorithms like Gay’s algorithm, Dragon4, or Grisu to
    | maintain exact bit-level precision without risking integer overflow.

    .


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From antispam@antispam@fricas.org (Waldek Hebisch) to comp.lang.c on Sat Jun 13 14:05:53 2026
    From Newsgroup: comp.lang.c

    Hans Bezemer <the.beez.speaks@gmail.com> wrote:
    Hi!

    The algorithms I've seen on the net require quite some bit hacking to
    get that done. Like: https://kyledewey.github.io/comp122-fall17/lecture/week_2/floating_point_interconversions.html

    I've designed the following algorithm which seems more straight forward.
    Now my question is: is this a reinvention of a known one -- or is this a
    new approach? Note that this works best with a large mantissa -- so I provided a word to normalize the mantissa/exponent pair, called normalize10().

    Saying "convert" is inprecise. Namely, on input you have rational
    number x = m*10^e (where '^' means power) and want rational number
    of form n*2^f. It is easy to prove that in general exact equality
    between two forms is impossible. So usual formulation is: find
    rational number of form n*2^e where bit size of n is limited by
    some fixed k which is closest to x. Solutions roughly fall into
    3 categories:
    - wrong ones, that is ones which do not give closest approximation
    - relatively easy slowish ones that use arbitrary precision arithmetic
    - complex ones which carefully use lowest precision to obtain
    correct result

    AFAICS you pretend that standard fixed precision arithmetic has
    enough precision, which in general is wrong.

    Also included: an integer version of pow(). BTW, no idea why it works,
    but it works for sane input values.

    Hans Bezemer

    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <limits.h>

    typedef struct {
    long long mantissa;
    long exponent;
    } me;

    long power (long base, long exp) /* integer version of pow() */
    {
    long long a = 1LL;

    do {
    if (exp & 1) a *= base;
    exp /= 2; base *= base;
    } while (exp != 0);

    return (a);
    }

    /* normalize mantissa/exponent */
    void normalize10 (me* zen, long long mant, long exp)
    { /* save sign of mantissa */
    char msign = (zen -> mantissa) < 0LL;
    /* get absolute value of mantissa */
    zen -> mantissa = llabs (zen -> mantissa);
    /* increase mantissa */
    while ((zen -> mantissa < mant) && (zen -> exponent > exp))
    { /* while between limits */
    zen -> mantissa *= 10; --(zen -> exponent);
    } /* multiply by 10 */
    /* correct mantissa sign if
    required */
    if (msign) zen -> mantissa = -(zen -> mantissa);
    }

    /* convert from radix 10 to
    radix 2 */
    void me10tome2 (me* zen)
    { /* save signs of mantissa and exponent */
    char msign = (zen -> mantissa) < 0LL;
    char esign = (zen -> exponent) < 0L;
    long exp2;

    long me10; /* radix 10 multiplication factor */
    long me2; /* radix 2 multiplication factor */

    if (zen -> exponent) { /* if exponent is non-zero */
    zen -> mantissa = llabs (zen -> mantissa);
    zen -> exponent = labs (zen -> exponent);
    /* get absolute value of
    mantissa and exponent */
    exp2 = (((zen -> exponent) * 10) + 2) / 3;
    /* convert exponent to radix 2 */
    me10 = power (10, zen -> exponent);
    me2 = 1 << exp2; /* calculate multiplication
    factors */

    if (esign) { /* if negative exponent */
    zen -> exponent = -exp2;
    zen -> mantissa = (zen -> mantissa * me2) / me10;
    } else { /* if positive exponent */
    zen -> exponent = exp2;
    zen -> mantissa = (zen -> mantissa * me10) / me2;
    }
    /* correct mantissa sign if
    required */
    if (msign) zen -> mantissa = -(zen -> mantissa);
    }
    }


    int main (int argc, char** argv)
    {
    me z = { 1000LL, -4L }; /* 1000E-4 */

    normalize10 (&z, LONG_MAX, -9); /* normalize mantissa and
    exponent */
    me10tome2 (&z); /* convert to radix 2 */
    /* check result */
    printf("Verification:\t%lld * 2^(%ld) = %f\n",
    z.mantissa, z.exponent, z.mantissa * pow(2.0, z.exponent));
    }

    --
    Waldek Hebisch
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From Rosario19@Ros@invalid.invalid to comp.lang.c on Mon Jun 15 11:34:53 2026
    From Newsgroup: comp.lang.c

    On Fri, 12 Jun 2026 21:08:05 +0200, Hans Bezemer wrote:

    Hi!

    The algorithms I've seen on the net require quite some bit hacking to
    get that done. Like: >https://kyledewey.github.io/comp122-fall17/lecture/week_2/floating_point_interconversions.html

    I've designed the following algorithm which seems more straight forward.
    Now my question is: is this a reinvention of a known one -- or is this a
    new approach? Note that this works best with a large mantissa -- so I >provided a word to normalize the mantissa/exponent pair, called >normalize10().

    Also included: an integer version of pow(). BTW, no idea why it works,
    but it works for sane input values.

    Hans Bezemer

    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include <limits.h>

    typedef struct {
    long long mantissa;
    long exponent;
    } me;

    long power (long base, long exp) /* integer version of pow() */
    {
    long long a = 1LL;

    do {
    if (exp & 1) a *= base;
    exp /= 2; base *= base;
    } while (exp != 0);

    return (a);
    }

    are you sure it is above and not below?

    long power (long base, long exp) /* integer version of pow() */
    {
    long long a = 1LL, b=base;

    do {
    if (exp & 1) a *= base;
    exp /= 2; base *= b;
    } while (exp != 0);

    return (a);
    }




    --- Synchronet 3.22a-Linux NewsLink 1.2