]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/Reliance-Edge/tests/util/math.c
Update Reliance Edge fail safe file system to the latest version.
[freertos] / FreeRTOS-Plus / Source / Reliance-Edge / tests / util / math.c
index e8f52015f349df376805e7a24180d279dd38ce09..00f6bc331640b21ffcfb3b3ca1e4eaee79d45ae5 100644 (file)
-/*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----\r
-\r
-                   Copyright (c) 2014-2015 Datalight, Inc.\r
-                       All Rights Reserved Worldwide.\r
-\r
-    This program is free software; you can redistribute it and/or modify\r
-    it under the terms of the GNU General Public License as published by\r
-    the Free Software Foundation; use version 2 of the License.\r
-\r
-    This program is distributed in the hope that it will be useful,\r
-    but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty\r
-    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-    GNU General Public License for more details.\r
-\r
-    You should have received a copy of the GNU General Public License along\r
-    with this program; if not, write to the Free Software Foundation, Inc.,\r
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\r
-*/\r
-/*  Businesses and individuals that for commercial or other reasons cannot\r
-    comply with the terms of the GPLv2 license may obtain a commercial license\r
-    before incorporating Reliance Edge into proprietary software for\r
-    distribution in any form.  Visit http://www.datalight.com/reliance-edge for\r
-    more information.\r
-*/\r
-/** @file\r
-    @brief Implements routines for certain 64-bit math operations and simulated\r
-           floating point.\r
-\r
-    RedUint64DivMod32() and RedUint64DivMod64() are derived from code at\r
-    http://www.hackersdelight.org.  This web site states explicitly that "You\r
-    are free to use, copy, and distribute any of the code on this web site,\r
-    whether modified by you or not.  You need not give attribution."\r
-*/\r
-#include <redfs.h>\r
-#include <redtestutils.h>\r
-\r
-\r
-static uint32_t nlz64(uint64_t ullValue);\r
-\r
-\r
-/** @brief Return a ratio value formatted as a floating point string accurate to\r
-           the specified number of decimal places.\r
-\r
-    The  function exists to provide floating point style output without using\r
-    any actual floating point types.\r
-\r
-    This function may scale the numbers down to avoid overflow at the high end.\r
-    Likewise, potential divide-by-zero errors are internally avoided.  Here are\r
-    some examples:\r
-\r
-    Dividend | Divisor | DecPlaces | Result\r
-    -------- | ------- | --------- | ------\r
-    12133    | 28545   | 2         | "0.42"\r
-    1539     | 506     | 2         | "3.04"\r
-\r
-    To get a number formatted as a percentage, take the take the portion of the\r
-    total (normally the smaller part), multiply it by 100, and pass it to this\r
-    function as the Dividend, pass the "total" value to this function as the\r
-    Divisor, and specify the desired number of decimal places.\r
-\r
-    For example, if you have a disk format overhead value of N blocks out of a\r
-    total of Y blocks on the disk, and you want to display the format overhead\r
-    as a percentage, you would use a function call\r
-    similar to:\r
-\r
-    ~~~{.c}\r
-    RedRatio(szBuffer, sizeof(szBuffer), N*100U, Y, 2U);\r
-    ~~~\r
-\r
-    If N=145, Y=4096, and decimal places is 2, the resulting output would be\r
-    "3.54".\r
-\r
-    The string returned will always be null-terminated, even if it means\r
-    stomping on the least significant decimal digit.\r
-\r
-    If either the dividend or divisor values are zero, the string "0.0" will be\r
-    returned, with the prescribed number of decimal places.\r
-\r
-    @note This function has "reasonable" limits which meet the needs of the\r
-          various supplemental utilities which use this function.  Extremely\r
-          large ratios, or using many decimal places may not function as\r
-          desired.\r
-\r
-    Parameters:\r
-    @param pBuffer      A pointer to the buffer in which to store the null\r
-                        terminated results.\r
-    @param ulBufferLen  The length of the output buffer.\r
-    @param ullDividend  The "total" value to divide.\r
-    @param ullDivisor   The portion of ullDividend for which to calculate the\r
-                        ratio (may be greater than ulDividend).\r
-    @param ulDecPlaces  The number of decimal places to use, from 0 to 9.\r
-\r
-    @return @p pBuffer.\r
-*/\r
-char *RedRatio(\r
-    char       *pBuffer,\r
-    uint32_t    ulBufferLen,\r
-    uint64_t    ullDividend,\r
-    uint64_t    ullDivisor,\r
-    uint32_t    ulDecPlaces)\r
-{\r
-    REDASSERT(pBuffer != NULL);\r
-    REDASSERT(ulBufferLen > 0U);\r
-    REDASSERT(ulDecPlaces <= 9U);   /* arbitrary */\r
-\r
-    if((ullDivisor > 0U) && (ullDividend > 0U))\r
-    {\r
-        uint32_t    ii;\r
-        uint32_t    ulFactor = 1U;\r
-        uint64_t    ullDecimal;\r
-        uint64_t    ullTemp;\r
-\r
-        for(ii = 1U; ii <= ulDecPlaces; ii++)\r
-        {\r
-            ulFactor *= 10U;\r
-        }\r
-\r
-        ullDecimal = RedMulDiv64(ullDividend, ulFactor, ullDivisor);\r
-\r
-        /*  Shouldn't really be calling this function in a situation where we\r
-            can overflow at this point...\r
-        */\r
-        REDASSERT(ullDecimal != UINT64_MAX);\r
-\r
-        if(ullDivisor <= ullDividend)\r
-        {\r
-            uint32_t ulDecimal;\r
-\r
-            (void)RedUint64DivMod32(ullDecimal, ulFactor, &ulDecimal);\r
-            ullDecimal = ulDecimal;\r
-        }\r
-\r
-        ullTemp = RedUint64DivMod64(ullDividend, ullDivisor, NULL);\r
-\r
-        if(ulDecPlaces > 0U)\r
-        {\r
-            RedSNPrintf(pBuffer, ulBufferLen, "%llu.%0*llu", (unsigned long long)ullTemp,\r
-                (unsigned)ulDecPlaces, (unsigned long long)ullDecimal);\r
-        }\r
-        else\r
-        {\r
-            RedSNPrintf(pBuffer, ulBufferLen, "%llu", (unsigned long long)ullTemp);\r
-        }\r
-    }\r
-    else\r
-    {\r
-        /*  If either the dividend or divisor is zero, then just output a "0.0"\r
-            string with the prescribed number of decimal places.\r
-        */\r
-        if(ulDecPlaces > 0U)\r
-        {\r
-            RedSNPrintf(pBuffer, ulBufferLen, "0.%0*u", (unsigned)ulDecPlaces, 0U);\r
-        }\r
-        else\r
-        {\r
-            RedStrNCpy(pBuffer, "0", ulBufferLen);\r
-        }\r
-    }\r
-\r
-    /*  Ensure the returned buffer is always null-terminated\r
-    */\r
-    pBuffer[ulBufferLen - 1U] = '\0';\r
-\r
-    return pBuffer;\r
-}\r
-\r
-\r
-/** @brief Multiply 64-bit and 32-bit numbers, and divide by a 64-bit number,\r
-           returning a 64-bit result.\r
-\r
-    @note This function may return an approximate value if multiplying\r
-          @p ullBase and @p ulMultplier results in a number larger than 64-bits\r
-          _and_ this cannot be avoided by scaling.\r
-\r
-    @param ullBase      The base 64-bit number number.\r
-    @param ulMultiplier The 32-bit number by which to multiply.\r
-    @param ullDivisor   The 64-bit number by which to divide.\r
-\r
-    @return The 64-bit unsigned integer result.  Always returns zero if either\r
-            @p ullBase or @p ulMultiplier are zero (regardless what\r
-            @p ullDivisor is).  Returns UINT64_MAX if an overflow condition\r
-            occurred, or if @p ullDivisor is zero.\r
-*/\r
-uint64_t RedMulDiv64(\r
-    uint64_t ullBase,\r
-    uint32_t ulMultiplier,\r
-    uint64_t ullDivisor)\r
-{\r
-    uint64_t ullTemp;\r
-\r
-    /*  Result would always be zero if either of these are zero.  Specifically\r
-        test this case before looking for a zero divisor.\r
-    */\r
-    if((ullBase == 0U) || (ulMultiplier == 0U))\r
-    {\r
-        return 0U;\r
-    }\r
-\r
-    if(ullDivisor == 0U)\r
-    {\r
-        return UINT64_MAX;\r
-    }\r
-\r
-    /*  Since we don't have the ability (yet) to use 128-bit numbers, we jump\r
-        through the following hoops (in order) to try to determine the proper\r
-        results without losing precision:\r
-\r
-        1) Shift the divisor and one of the multiplicands as many times as is\r
-           necessary to reduce the scale -- only if it can be done without\r
-           losing precision.\r
-        2) Divide one of the multiplicands by the divisor first, but only if it\r
-           divides evenly, preserving precision.\r
-        3) Same as #2, but try it for the other multiplicand.\r
-        4) Last ditch, divide the larger multiplicand by the divisor first, then\r
-           do the multiply.  This <WILL> lose precision.\r
-\r
-        These solutions are identified as CODE-PATHs #1-4 which are used to\r
-        identify the matching tests in dltmain.c.\r
-\r
-        Note that execution might partially include CODE-PATH #1 up until\r
-        shifting can no longer be done without losing precision.  In that case,\r
-        one of the three remaining options will be used.\r
-    */\r
-\r
-    ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);\r
-    while(ullBase > ullTemp)\r
-    {\r
-        uint64_t ullMod;\r
-        uint64_t ullBaseTemp;\r
-        uint64_t ullWideMultiplier;\r
-\r
-        /*  CODE-PATH #1\r
-        */\r
-        /*  So long as ulDivisor, and at least one of the other numbers, are\r
-            evenly divisible by 2, we can scale the numbers so the result does\r
-            not overflow the intermediate 64-bit value.\r
-        */\r
-        if((ullDivisor & 1U) == 0U)\r
-        {\r
-            if((ullBase & 1U) == 0U)\r
-            {\r
-                /*  CODE-PATH #1a\r
-                */\r
-                ullDivisor >>= 1U;\r
-                ullBase >>= 1U;\r
-                continue;\r
-            }\r
-\r
-            if(((ulMultiplier & 1U) == 0U) && ((ullTemp & UINT64_SUFFIX(0x8000000000000000)) == 0U))\r
-            {\r
-                /*  CODE-PATH #1b\r
-                */\r
-                ullDivisor >>= 1U;\r
-                ulMultiplier >>= 1U;\r
-                ullTemp <<= 1U;\r
-                continue;\r
-            }\r
-        }\r
-\r
-        /*  If we get to this point, the above method (#1) cannot be used\r
-            because not enough of the numbers are even long enough to scale the\r
-            operands down.  We'll see if either multiplicand is evenly divisble\r
-            by ulDivisor, and if so, do the divide first, then the multiply.\r
-            (Note that once we get to this point, we will never exercise the\r
-            while{} loop anymore.)\r
-        */\r
-\r
-        /*  CODE-PATH #2\r
-        */\r
-        ullBaseTemp = RedUint64DivMod64(ullBase, ullDivisor, &ullMod);\r
-        if(ullMod == 0U)\r
-        {\r
-            /*  Evenly divides, so check that we won't overflow, and finish up.\r
-            */\r
-            ullBase = ullBaseTemp;\r
-            if(ullBase > ullTemp)\r
-            {\r
-                return UINT64_MAX;\r
-            }\r
-            else\r
-            {\r
-                /*  We've validated that this will not overflow.\r
-                */\r
-                ullBase *= ulMultiplier;\r
-                return ullBase;\r
-            }\r
-        }\r
-\r
-        /*  CODE-PATH #3\r
-        */\r
-        ullWideMultiplier = RedUint64DivMod64(ulMultiplier, ullDivisor, &ullMod);\r
-        if(ullMod == 0U)\r
-        {\r
-            /*  Evenly divides, so check that we won't overflow, and finish up.\r
-            */\r
-\r
-            /*  Must recalculate ullTemp relative to ullBase\r
-            */\r
-            ullTemp = RedUint64DivMod64(UINT64_MAX, ullBase, NULL);\r
-            if(ullWideMultiplier > ullTemp)\r
-            {\r
-                return UINT64_MAX;\r
-            }\r
-            else\r
-            {\r
-                uint32_t ulNarrowMultiplier = (uint32_t)ullWideMultiplier;\r
-\r
-                /*  We've validated that this will not overflow.\r
-                */\r
-                ullBase *= ulNarrowMultiplier;\r
-                return ullBase;\r
-            }\r
-        }\r
-\r
-        /*  CODE-PATH #4\r
-\r
-            Neither of the multipliers is evenly divisible by the divisor, so\r
-            just punt and divide the larger number first, then do the final\r
-            multiply.\r
-\r
-            All the other attempts above would preserve precision -- this is the\r
-            only case where precision may be lost.\r
-        */\r
-\r
-        /*  If necessary reverse the ullBase and ulMultiplier operands so that\r
-            ullBase contains the larger of the two values.\r
-        */\r
-        if(ullBase < ulMultiplier)\r
-        {\r
-            uint32_t ulTemp = ulMultiplier;\r
-\r
-            ulMultiplier = (uint32_t)ullBase;\r
-            ullBase = ulTemp;\r
-        }\r
-\r
-        ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);\r
-        ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);\r
-        if(ullBase > ullTemp)\r
-        {\r
-            return UINT64_MAX;\r
-        }\r
-        else\r
-        {\r
-            ullBase *= ulMultiplier;\r
-            return ullBase;\r
-        }\r
-    }\r
-\r
-    /*  We only get to this point if either there was never any chance of\r
-        overflow, or if the pure shifting mechanism succeeded in reducing\r
-        the scale so overflow is not a problem.\r
-    */\r
-\r
-    ullBase *= ulMultiplier;\r
-    ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);\r
-\r
-    return ullBase;\r
-}\r
-\r
-\r
-/** @brief Divide a 64-bit value by a 32-bit value, returning the quotient and\r
-           the remainder.\r
-\r
-    Essentially this function does the following:\r
-\r
-    ~~~{.c}\r
-    if(pulRemainder != NULL)\r
-    {\r
-        *pulRemainder = (uint32_t)(ullDividend % ulDivisor);\r
-    }\r
-    return ullDividend / ulDivisor;\r
-    ~~~\r
-\r
-    However, it does so without ever actually dividing/modulating a 64-bit\r
-    value, since such operations are not allowed in all environments.\r
-\r
-    @param ullDividend  The value to divide.\r
-    @param ulDivisor    The value to divide by.\r
-    @param pulRemander  Populated with the remainder; may be NULL.\r
-\r
-    @return The quotient (result of the division).\r
-*/\r
-uint64_t RedUint64DivMod32(\r
-    uint64_t    ullDividend,\r
-    uint32_t    ulDivisor,\r
-    uint32_t   *pulRemainder)\r
-{\r
-    uint64_t    ullQuotient;\r
-    uint32_t    ulResultRemainder;\r
-\r
-    /*  Check for divide by zero.\r
-    */\r
-    if(ulDivisor == 0U)\r
-    {\r
-        REDERROR();\r
-\r
-        /*  Nonsense value if no asserts.\r
-        */\r
-        ullQuotient = UINT64_SUFFIX(0xFFFFFFFFFFFFFBAD);\r
-        ulResultRemainder = 0xFFFFFBADU;\r
-    }\r
-    else if(ullDividend <= UINT32_MAX)\r
-    {\r
-        uint32_t ulDividend = (uint32_t)ullDividend;\r
-\r
-        ullQuotient = ulDividend / ulDivisor;\r
-        ulResultRemainder = ulDividend % ulDivisor;\r
-    }\r
-    else\r
-    {\r
-        uint32_t    ulResultHi;\r
-        uint32_t    ulResultLo;\r
-        uint32_t    ulRemainder;\r
-        uint8_t     bIndex;\r
-        uint32_t    ulThisDivision;\r
-        uint32_t    ulMask;\r
-        uint8_t     ucNextValue;\r
-        uint32_t    ulInterimHi, ulInterimLo;\r
-        uint32_t    ulLowDword = (uint32_t)ullDividend;\r
-        uint32_t    ulHighDword = (uint32_t)(ullDividend >> 32U);\r
-\r
-        /*  Compute the high part and get the remainder\r
-        */\r
-        ulResultHi = ulHighDword / ulDivisor;\r
-        ulResultLo = 0U;\r
-        ulRemainder = ulHighDword % ulDivisor;\r
-\r
-        /*  Compute the low part\r
-        */\r
-        ulMask = 0xFF000000U;\r
-        for(bIndex = 0U; bIndex < sizeof(uint32_t); bIndex++)\r
-        {\r
-            ucNextValue = (uint8_t)((ulLowDword & ulMask) >> ((sizeof(uint32_t) - 1U - bIndex) * 8U));\r
-            ulInterimHi = ulRemainder >> 24U;\r
-            ulInterimLo = (ulRemainder << 8U) | ucNextValue;\r
-            ulThisDivision = 0U;\r
-            while(ulInterimHi != 0U)\r
-            {\r
-                uint64_t ullInterim = ((uint64_t)ulInterimHi << 32U) + ulInterimLo;\r
-\r
-                ullInterim -= ulDivisor;\r
-                ulThisDivision++;\r
-\r
-                ulInterimHi = (uint32_t)(ullInterim >> 32U);\r
-                ulInterimLo = (uint32_t)ullInterim;\r
-            }\r
-            ulThisDivision += ulInterimLo / ulDivisor;\r
-            ulRemainder = ulInterimLo % ulDivisor;\r
-            ulResultLo <<= 8U;\r
-            ulResultLo += ulThisDivision;\r
-            ulMask >>= 8U;\r
-        }\r
-\r
-        ullQuotient = ((uint64_t)ulResultHi << 32U) + ulResultLo;\r
-        ulResultRemainder = (uint32_t)(ullDividend - (ullQuotient * ulDivisor));\r
-    }\r
-\r
-    if(pulRemainder != NULL)\r
-    {\r
-        *pulRemainder = ulResultRemainder;\r
-    }\r
-\r
-    return ullQuotient;\r
-}\r
-\r
-\r
-/** @brief Divide a 64-bit value by a 64-bit value, returning the quotient and\r
-           the remainder.\r
-\r
-    Essentially this function does the following:\r
-\r
-    ~~~{.c}\r
-    if(pullRemainder != NULL)\r
-    {\r
-        *pullRemainder = ullDividend % ullDivisor;\r
-    }\r
-    return ullDividend / ullDivisor;\r
-    ~~~\r
-\r
-    However, it does so without ever actually dividing/modulating a 64-bit\r
-    value, since such operations are not allowed in all environments.\r
-\r
-    @param ullDividend  The value to divide.\r
-    @param ullDivisor   The value to divide by.\r
-    @param pullRemander Populated with the remainder; may be NULL.\r
-\r
-    @return The quotient (result of the division).\r
-*/\r
-uint64_t RedUint64DivMod64(\r
-    uint64_t    ullDividend,\r
-    uint64_t    ullDivisor,\r
-    uint64_t   *pullRemainder)\r
-{\r
-    /*  The variables u0, u1, etc. take on only 32-bit values, but they are\r
-        declared uint64_t to avoid some compiler warning messages and to avoid\r
-        some unnecessary EXTRs that the compiler would put in, to convert\r
-        uint64_ts to ints.\r
-    */\r
-    uint64_t    u0;\r
-    uint64_t    u1;\r
-    uint64_t    q0;\r
-    uint64_t    q1;\r
-    uint64_t    ullQuotient;\r
-\r
-    /*  First the procedure takes care of the case in which the divisor is a\r
-        32-bit quantity.  There are two subcases: (1) If the left half of the\r
-        dividend is less than the divisor, one execution of RedUint64DivMod32()\r
-        is all that is required (overflow is not possible). (2) Otherwise it\r
-        does two divisions, using the grade school method.\r
-    */\r
-\r
-    if((ullDivisor >> 32U) == 0U)\r
-    {\r
-        if((ullDividend >> 32U) < ullDivisor)\r
-        {\r
-            /*  If ullDividend/ullDivisor cannot overflow, just do one division.\r
-            */\r
-            ullQuotient = RedUint64DivMod32(ullDividend, (uint32_t)ullDivisor, NULL);\r
-        }\r
-        else\r
-        {\r
-            uint32_t k;\r
-\r
-            /*  If ullDividend/ullDivisor would overflow:\r
-            */\r
-\r
-            /*  Break ullDividend up into two halves.\r
-            */\r
-            u1 = ullDividend >> 32U;\r
-            u0 = ullDividend & 0xFFFFFFFFU;\r
-\r
-            /*  First quotient digit and first remainder.\r
-            */\r
-            q1 = RedUint64DivMod32(u1, (uint32_t)ullDivisor, &k);\r
-\r
-            /*  2nd quot. digit.\r
-            */\r
-            q0 = RedUint64DivMod32(((uint64_t)k << 32U) + u0, (uint32_t)ullDivisor, NULL);\r
-\r
-            ullQuotient = (q1 << 32U) + q0;\r
-        }\r
-    }\r
-    else\r
-    {\r
-        uint64_t n;\r
-        uint64_t v1;\r
-\r
-        n = nlz64(ullDivisor);          /* 0 <= n <= 31. */\r
-        v1 = (ullDivisor << n) >> 32U;  /* Normalize the divisor so its MSB is 1. */\r
-        u1 = ullDividend >> 1U;         /* To ensure no overflow. */\r
-\r
-        /*  Get quotient from divide unsigned insn.\r
-        */\r
-        q1 = RedUint64DivMod32(u1, (uint32_t)v1, NULL);\r
-\r
-        q0 = (q1 << n) >> 31U;  /* Undo normalization and division of ullDividend by 2. */\r
-\r
-        /*  Make q0 correct or too small by 1.\r
-        */\r
-        if(q0 != 0U)\r
-        {\r
-            q0--;\r
-        }\r
-\r
-        if((ullDividend - (q0 * ullDivisor)) >= ullDivisor)\r
-        {\r
-            q0++;   /* Now q0 is correct. */\r
-        }\r
-\r
-        ullQuotient = q0;\r
-    }\r
-\r
-    if(pullRemainder != NULL)\r
-    {\r
-        *pullRemainder = ullDividend - (ullQuotient * ullDivisor);\r
-    }\r
-\r
-    return ullQuotient;\r
-}\r
-\r
-\r
-/** @brief Compute the number of leading zeroes in a 64-bit value.\r
-\r
-    @param ullValue The value for which to compute the NLZ.\r
-\r
-    @return The number of leading zeroes in @p ullValue.\r
-*/\r
-static uint32_t nlz64(\r
-    uint64_t    ullValue)\r
-{\r
-    uint32_t    n;\r
-\r
-    if(ullValue == 0U)\r
-    {\r
-        n = 64U;\r
-    }\r
-    else\r
-    {\r
-        uint64_t x = ullValue;\r
-\r
-        n = 0U;\r
-\r
-        if(x <= UINT64_SUFFIX(0x00000000FFFFFFFF))\r
-        {\r
-            n += 32U;\r
-            x <<= 32U;\r
-        }\r
-\r
-        if(x <= UINT64_SUFFIX(0x0000FFFFFFFFFFFF))\r
-        {\r
-            n += 16U;\r
-            x <<= 16U;\r
-        }\r
-\r
-        if(x <= UINT64_SUFFIX(0x00FFFFFFFFFFFFFF))\r
-        {\r
-            n += 8U;\r
-            x <<= 8U;\r
-        }\r
-\r
-        if(x <= UINT64_SUFFIX(0x0FFFFFFFFFFFFFFF))\r
-        {\r
-            n += 4U;\r
-            x <<= 4U;\r
-        }\r
-\r
-        if(x <= UINT64_SUFFIX(0x3FFFFFFFFFFFFFFF))\r
-        {\r
-            n += 2U;\r
-            x <<= 2U;\r
-        }\r
-\r
-        if(x <= UINT64_SUFFIX(0x7FFFFFFFFFFFFFFF))\r
-        {\r
-            n += 1;\r
-        }\r
-    }\r
-\r
-    return n;\r
-}\r
-\r
+/*             ----> DO NOT REMOVE THE FOLLOWING NOTICE <----
+
+                   Copyright (c) 2014-2015 Datalight, Inc.
+                       All Rights Reserved Worldwide.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; use version 2 of the License.
+
+    This program is distributed in the hope that it will be useful,
+    but "AS-IS," WITHOUT ANY WARRANTY; without even the implied warranty
+    of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+/*  Businesses and individuals that for commercial or other reasons cannot
+    comply with the terms of the GPLv2 license may obtain a commercial license
+    before incorporating Reliance Edge into proprietary software for
+    distribution in any form.  Visit http://www.datalight.com/reliance-edge for
+    more information.
+*/
+/** @file
+    @brief Implements routines for certain 64-bit math operations and simulated
+           floating point.
+
+    RedUint64DivMod32() and RedUint64DivMod64() are derived from code at
+    http://www.hackersdelight.org.  This web site states explicitly that "You
+    are free to use, copy, and distribute any of the code on this web site,
+    whether modified by you or not.  You need not give attribution."
+*/
+#include <redfs.h>
+#include <redtestutils.h>
+
+
+static uint32_t nlz64(uint64_t ullValue);
+
+
+/** @brief Return a ratio value formatted as a floating point string accurate to
+           the specified number of decimal places.
+
+    The  function exists to provide floating point style output without using
+    any actual floating point types.
+
+    This function may scale the numbers down to avoid overflow at the high end.
+    Likewise, potential divide-by-zero errors are internally avoided.  Here are
+    some examples:
+
+    Dividend | Divisor | DecPlaces | Result
+    -------- | ------- | --------- | ------
+    12133    | 28545   | 2         | "0.42"
+    1539     | 506     | 2         | "3.04"
+
+    To get a number formatted as a percentage, take the take the portion of the
+    total (normally the smaller part), multiply it by 100, and pass it to this
+    function as the Dividend, pass the "total" value to this function as the
+    Divisor, and specify the desired number of decimal places.
+
+    For example, if you have a disk format overhead value of N blocks out of a
+    total of Y blocks on the disk, and you want to display the format overhead
+    as a percentage, you would use a function call
+    similar to:
+
+    ~~~{.c}
+    RedRatio(szBuffer, sizeof(szBuffer), N*100U, Y, 2U);
+    ~~~
+
+    If N=145, Y=4096, and decimal places is 2, the resulting output would be
+    "3.54".
+
+    The string returned will always be null-terminated, even if it means
+    stomping on the least significant decimal digit.
+
+    If either the dividend or divisor values are zero, the string "0.0" will be
+    returned, with the prescribed number of decimal places.
+
+    @note This function has "reasonable" limits which meet the needs of the
+          various supplemental utilities which use this function.  Extremely
+          large ratios, or using many decimal places may not function as
+          desired.
+
+    Parameters:
+    @param pBuffer      A pointer to the buffer in which to store the null
+                        terminated results.
+    @param ulBufferLen  The length of the output buffer.
+    @param ullDividend  The "total" value to divide.
+    @param ullDivisor   The portion of ullDividend for which to calculate the
+                        ratio (may be greater than ulDividend).
+    @param ulDecPlaces  The number of decimal places to use, from 0 to 9.
+
+    @return @p pBuffer.
+*/
+char *RedRatio(
+    char       *pBuffer,
+    uint32_t    ulBufferLen,
+    uint64_t    ullDividend,
+    uint64_t    ullDivisor,
+    uint32_t    ulDecPlaces)
+{
+    REDASSERT(pBuffer != NULL);
+    REDASSERT(ulBufferLen > 0U);
+    REDASSERT(ulDecPlaces <= 9U);   /* arbitrary */
+
+    if((ullDivisor > 0U) && (ullDividend > 0U))
+    {
+        uint32_t    ii;
+        uint32_t    ulFactor = 1U;
+        uint64_t    ullDecimal;
+        uint64_t    ullTemp;
+
+        for(ii = 1U; ii <= ulDecPlaces; ii++)
+        {
+            ulFactor *= 10U;
+        }
+
+        ullDecimal = RedMulDiv64(ullDividend, ulFactor, ullDivisor);
+
+        /*  Shouldn't really be calling this function in a situation where we
+            can overflow at this point...
+        */
+        REDASSERT(ullDecimal != UINT64_MAX);
+
+        if(ullDivisor <= ullDividend)
+        {
+            uint32_t ulDecimal;
+
+            (void)RedUint64DivMod32(ullDecimal, ulFactor, &ulDecimal);
+            ullDecimal = ulDecimal;
+        }
+
+        ullTemp = RedUint64DivMod64(ullDividend, ullDivisor, NULL);
+
+        if(ulDecPlaces > 0U)
+        {
+            RedSNPrintf(pBuffer, ulBufferLen, "%llu.%0*llu", (unsigned long long)ullTemp,
+                (unsigned)ulDecPlaces, (unsigned long long)ullDecimal);
+        }
+        else
+        {
+            RedSNPrintf(pBuffer, ulBufferLen, "%llu", (unsigned long long)ullTemp);
+        }
+    }
+    else
+    {
+        /*  If either the dividend or divisor is zero, then just output a "0.0"
+            string with the prescribed number of decimal places.
+        */
+        if(ulDecPlaces > 0U)
+        {
+            RedSNPrintf(pBuffer, ulBufferLen, "0.%0*u", (unsigned)ulDecPlaces, 0U);
+        }
+        else
+        {
+            RedStrNCpy(pBuffer, "0", ulBufferLen);
+        }
+    }
+
+    /*  Ensure the returned buffer is always null-terminated
+    */
+    pBuffer[ulBufferLen - 1U] = '\0';
+
+    return pBuffer;
+}
+
+
+/** @brief Multiply 64-bit and 32-bit numbers, and divide by a 64-bit number,
+           returning a 64-bit result.
+
+    @note This function may return an approximate value if multiplying
+          @p ullBase and @p ulMultplier results in a number larger than 64-bits
+          _and_ this cannot be avoided by scaling.
+
+    @param ullBase      The base 64-bit number number.
+    @param ulMultiplier The 32-bit number by which to multiply.
+    @param ullDivisor   The 64-bit number by which to divide.
+
+    @return The 64-bit unsigned integer result.  Always returns zero if either
+            @p ullBase or @p ulMultiplier are zero (regardless what
+            @p ullDivisor is).  Returns UINT64_MAX if an overflow condition
+            occurred, or if @p ullDivisor is zero.
+*/
+uint64_t RedMulDiv64(
+    uint64_t ullBase,
+    uint32_t ulMultiplier,
+    uint64_t ullDivisor)
+{
+    uint64_t ullTemp;
+
+    /*  Result would always be zero if either of these are zero.  Specifically
+        test this case before looking for a zero divisor.
+    */
+    if((ullBase == 0U) || (ulMultiplier == 0U))
+    {
+        return 0U;
+    }
+
+    if(ullDivisor == 0U)
+    {
+        return UINT64_MAX;
+    }
+
+    /*  Since we don't have the ability (yet) to use 128-bit numbers, we jump
+        through the following hoops (in order) to try to determine the proper
+        results without losing precision:
+
+        1) Shift the divisor and one of the multiplicands as many times as is
+           necessary to reduce the scale -- only if it can be done without
+           losing precision.
+        2) Divide one of the multiplicands by the divisor first, but only if it
+           divides evenly, preserving precision.
+        3) Same as #2, but try it for the other multiplicand.
+        4) Last ditch, divide the larger multiplicand by the divisor first, then
+           do the multiply.  This <WILL> lose precision.
+
+        These solutions are identified as CODE-PATHs #1-4 which are used to
+        identify the matching tests in dltmain.c.
+
+        Note that execution might partially include CODE-PATH #1 up until
+        shifting can no longer be done without losing precision.  In that case,
+        one of the three remaining options will be used.
+    */
+
+    ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);
+    while(ullBase > ullTemp)
+    {
+        uint64_t ullMod;
+        uint64_t ullBaseTemp;
+        uint64_t ullWideMultiplier;
+
+        /*  CODE-PATH #1
+        */
+        /*  So long as ulDivisor, and at least one of the other numbers, are
+            evenly divisible by 2, we can scale the numbers so the result does
+            not overflow the intermediate 64-bit value.
+        */
+        if((ullDivisor & 1U) == 0U)
+        {
+            if((ullBase & 1U) == 0U)
+            {
+                /*  CODE-PATH #1a
+                */
+                ullDivisor >>= 1U;
+                ullBase >>= 1U;
+                continue;
+            }
+
+            if(((ulMultiplier & 1U) == 0U) && ((ullTemp & UINT64_SUFFIX(0x8000000000000000)) == 0U))
+            {
+                /*  CODE-PATH #1b
+                */
+                ullDivisor >>= 1U;
+                ulMultiplier >>= 1U;
+                ullTemp <<= 1U;
+                continue;
+            }
+        }
+
+        /*  If we get to this point, the above method (#1) cannot be used
+            because not enough of the numbers are even long enough to scale the
+            operands down.  We'll see if either multiplicand is evenly divisble
+            by ulDivisor, and if so, do the divide first, then the multiply.
+            (Note that once we get to this point, we will never exercise the
+            while{} loop anymore.)
+        */
+
+        /*  CODE-PATH #2
+        */
+        ullBaseTemp = RedUint64DivMod64(ullBase, ullDivisor, &ullMod);
+        if(ullMod == 0U)
+        {
+            /*  Evenly divides, so check that we won't overflow, and finish up.
+            */
+            ullBase = ullBaseTemp;
+            if(ullBase > ullTemp)
+            {
+                return UINT64_MAX;
+            }
+            else
+            {
+                /*  We've validated that this will not overflow.
+                */
+                ullBase *= ulMultiplier;
+                return ullBase;
+            }
+        }
+
+        /*  CODE-PATH #3
+        */
+        ullWideMultiplier = RedUint64DivMod64(ulMultiplier, ullDivisor, &ullMod);
+        if(ullMod == 0U)
+        {
+            /*  Evenly divides, so check that we won't overflow, and finish up.
+            */
+
+            /*  Must recalculate ullTemp relative to ullBase
+            */
+            ullTemp = RedUint64DivMod64(UINT64_MAX, ullBase, NULL);
+            if(ullWideMultiplier > ullTemp)
+            {
+                return UINT64_MAX;
+            }
+            else
+            {
+                uint32_t ulNarrowMultiplier = (uint32_t)ullWideMultiplier;
+
+                /*  We've validated that this will not overflow.
+                */
+                ullBase *= ulNarrowMultiplier;
+                return ullBase;
+            }
+        }
+
+        /*  CODE-PATH #4
+
+            Neither of the multipliers is evenly divisible by the divisor, so
+            just punt and divide the larger number first, then do the final
+            multiply.
+
+            All the other attempts above would preserve precision -- this is the
+            only case where precision may be lost.
+        */
+
+        /*  If necessary reverse the ullBase and ulMultiplier operands so that
+            ullBase contains the larger of the two values.
+        */
+        if(ullBase < ulMultiplier)
+        {
+            uint32_t ulTemp = ulMultiplier;
+
+            ulMultiplier = (uint32_t)ullBase;
+            ullBase = ulTemp;
+        }
+
+        ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);
+        ullTemp = RedUint64DivMod32(UINT64_MAX, ulMultiplier, NULL);
+        if(ullBase > ullTemp)
+        {
+            return UINT64_MAX;
+        }
+        else
+        {
+            ullBase *= ulMultiplier;
+            return ullBase;
+        }
+    }
+
+    /*  We only get to this point if either there was never any chance of
+        overflow, or if the pure shifting mechanism succeeded in reducing
+        the scale so overflow is not a problem.
+    */
+
+    ullBase *= ulMultiplier;
+    ullBase = RedUint64DivMod64(ullBase, ullDivisor, NULL);
+
+    return ullBase;
+}
+
+
+/** @brief Divide a 64-bit value by a 32-bit value, returning the quotient and
+           the remainder.
+
+    Essentially this function does the following:
+
+    ~~~{.c}
+    if(pulRemainder != NULL)
+    {
+        *pulRemainder = (uint32_t)(ullDividend % ulDivisor);
+    }
+    return ullDividend / ulDivisor;
+    ~~~
+
+    However, it does so without ever actually dividing/modulating a 64-bit
+    value, since such operations are not allowed in all environments.
+
+    @param ullDividend  The value to divide.
+    @param ulDivisor    The value to divide by.
+    @param pulRemainder Populated with the remainder; may be NULL.
+
+    @return The quotient (result of the division).
+*/
+uint64_t RedUint64DivMod32(
+    uint64_t    ullDividend,
+    uint32_t    ulDivisor,
+    uint32_t   *pulRemainder)
+{
+    uint64_t    ullQuotient;
+    uint32_t    ulResultRemainder;
+
+    /*  Check for divide by zero.
+    */
+    if(ulDivisor == 0U)
+    {
+        REDERROR();
+
+        /*  Nonsense value if no asserts.
+        */
+        ullQuotient = UINT64_SUFFIX(0xFFFFFFFFFFFFFBAD);
+        ulResultRemainder = 0xFFFFFBADU;
+    }
+    else if(ullDividend <= UINT32_MAX)
+    {
+        uint32_t ulDividend = (uint32_t)ullDividend;
+
+        ullQuotient = ulDividend / ulDivisor;
+        ulResultRemainder = ulDividend % ulDivisor;
+    }
+    else
+    {
+        uint32_t    ulResultHi;
+        uint32_t    ulResultLo;
+        uint32_t    ulRemainder;
+        uint8_t     bIndex;
+        uint32_t    ulThisDivision;
+        uint32_t    ulMask;
+        uint8_t     ucNextValue;
+        uint32_t    ulInterimHi, ulInterimLo;
+        uint32_t    ulLowDword = (uint32_t)ullDividend;
+        uint32_t    ulHighDword = (uint32_t)(ullDividend >> 32U);
+
+        /*  Compute the high part and get the remainder
+        */
+        ulResultHi = ulHighDword / ulDivisor;
+        ulResultLo = 0U;
+        ulRemainder = ulHighDword % ulDivisor;
+
+        /*  Compute the low part
+        */
+        ulMask = 0xFF000000U;
+        for(bIndex = 0U; bIndex < sizeof(uint32_t); bIndex++)
+        {
+            ucNextValue = (uint8_t)((ulLowDword & ulMask) >> ((sizeof(uint32_t) - 1U - bIndex) * 8U));
+            ulInterimHi = ulRemainder >> 24U;
+            ulInterimLo = (ulRemainder << 8U) | ucNextValue;
+            ulThisDivision = 0U;
+            while(ulInterimHi != 0U)
+            {
+                uint64_t ullInterim = ((uint64_t)ulInterimHi << 32U) + ulInterimLo;
+
+                ullInterim -= ulDivisor;
+                ulThisDivision++;
+
+                ulInterimHi = (uint32_t)(ullInterim >> 32U);
+                ulInterimLo = (uint32_t)ullInterim;
+            }
+            ulThisDivision += ulInterimLo / ulDivisor;
+            ulRemainder = ulInterimLo % ulDivisor;
+            ulResultLo <<= 8U;
+            ulResultLo += ulThisDivision;
+            ulMask >>= 8U;
+        }
+
+        ullQuotient = ((uint64_t)ulResultHi << 32U) + ulResultLo;
+        ulResultRemainder = (uint32_t)(ullDividend - (ullQuotient * ulDivisor));
+    }
+
+    if(pulRemainder != NULL)
+    {
+        *pulRemainder = ulResultRemainder;
+    }
+
+    return ullQuotient;
+}
+
+
+/** @brief Divide a 64-bit value by a 64-bit value, returning the quotient and
+           the remainder.
+
+    Essentially this function does the following:
+
+    ~~~{.c}
+    if(pullRemainder != NULL)
+    {
+        *pullRemainder = ullDividend % ullDivisor;
+    }
+    return ullDividend / ullDivisor;
+    ~~~
+
+    However, it does so without ever actually dividing/modulating a 64-bit
+    value, since such operations are not allowed in all environments.
+
+    @param ullDividend   The value to divide.
+    @param ullDivisor    The value to divide by.
+    @param pullRemainder Populated with the remainder; may be NULL.
+
+    @return The quotient (result of the division).
+*/
+uint64_t RedUint64DivMod64(
+    uint64_t    ullDividend,
+    uint64_t    ullDivisor,
+    uint64_t   *pullRemainder)
+{
+    /*  The variables u0, u1, etc. take on only 32-bit values, but they are
+        declared uint64_t to avoid some compiler warning messages and to avoid
+        some unnecessary EXTRs that the compiler would put in, to convert
+        uint64_ts to ints.
+    */
+    uint64_t    u0;
+    uint64_t    u1;
+    uint64_t    q0;
+    uint64_t    q1;
+    uint64_t    ullQuotient;
+
+    /*  First the procedure takes care of the case in which the divisor is a
+        32-bit quantity.  There are two subcases: (1) If the left half of the
+        dividend is less than the divisor, one execution of RedUint64DivMod32()
+        is all that is required (overflow is not possible). (2) Otherwise it
+        does two divisions, using the grade school method.
+    */
+
+    if((ullDivisor >> 32U) == 0U)
+    {
+        if((ullDividend >> 32U) < ullDivisor)
+        {
+            /*  If ullDividend/ullDivisor cannot overflow, just do one division.
+            */
+            ullQuotient = RedUint64DivMod32(ullDividend, (uint32_t)ullDivisor, NULL);
+        }
+        else
+        {
+            uint32_t k;
+
+            /*  If ullDividend/ullDivisor would overflow:
+            */
+
+            /*  Break ullDividend up into two halves.
+            */
+            u1 = ullDividend >> 32U;
+            u0 = ullDividend & 0xFFFFFFFFU;
+
+            /*  First quotient digit and first remainder.
+            */
+            q1 = RedUint64DivMod32(u1, (uint32_t)ullDivisor, &k);
+
+            /*  2nd quot. digit.
+            */
+            q0 = RedUint64DivMod32(((uint64_t)k << 32U) + u0, (uint32_t)ullDivisor, NULL);
+
+            ullQuotient = (q1 << 32U) + q0;
+        }
+    }
+    else
+    {
+        uint64_t n;
+        uint64_t v1;
+
+        n = nlz64(ullDivisor);          /* 0 <= n <= 31. */
+        v1 = (ullDivisor << n) >> 32U;  /* Normalize the divisor so its MSB is 1. */
+        u1 = ullDividend >> 1U;         /* To ensure no overflow. */
+
+        /*  Get quotient from divide unsigned insn.
+        */
+        q1 = RedUint64DivMod32(u1, (uint32_t)v1, NULL);
+
+        q0 = (q1 << n) >> 31U;  /* Undo normalization and division of ullDividend by 2. */
+
+        /*  Make q0 correct or too small by 1.
+        */
+        if(q0 != 0U)
+        {
+            q0--;
+        }
+
+        if((ullDividend - (q0 * ullDivisor)) >= ullDivisor)
+        {
+            q0++;   /* Now q0 is correct. */
+        }
+
+        ullQuotient = q0;
+    }
+
+    if(pullRemainder != NULL)
+    {
+        *pullRemainder = ullDividend - (ullQuotient * ullDivisor);
+    }
+
+    return ullQuotient;
+}
+
+
+/** @brief Compute the number of leading zeroes in a 64-bit value.
+
+    @param ullValue The value for which to compute the NLZ.
+
+    @return The number of leading zeroes in @p ullValue.
+*/
+static uint32_t nlz64(
+    uint64_t    ullValue)
+{
+    uint32_t    n;
+
+    if(ullValue == 0U)
+    {
+        n = 64U;
+    }
+    else
+    {
+        uint64_t x = ullValue;
+
+        n = 0U;
+
+        if(x <= UINT64_SUFFIX(0x00000000FFFFFFFF))
+        {
+            n += 32U;
+            x <<= 32U;
+        }
+
+        if(x <= UINT64_SUFFIX(0x0000FFFFFFFFFFFF))
+        {
+            n += 16U;
+            x <<= 16U;
+        }
+
+        if(x <= UINT64_SUFFIX(0x00FFFFFFFFFFFFFF))
+        {
+            n += 8U;
+            x <<= 8U;
+        }
+
+        if(x <= UINT64_SUFFIX(0x0FFFFFFFFFFFFFFF))
+        {
+            n += 4U;
+            x <<= 4U;
+        }
+
+        if(x <= UINT64_SUFFIX(0x3FFFFFFFFFFFFFFF))
+        {
+            n += 2U;
+            x <<= 2U;
+        }
+
+        if(x <= UINT64_SUFFIX(0x7FFFFFFFFFFFFFFF))
+        {
+            n += 1;
+        }
+    }
+
+    return n;
+}
+