Initial version
This commit is contained in:
@ -0,0 +1,478 @@
|
||||
/* ----> 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 utilities that convert strings to numbers.
|
||||
*/
|
||||
#include <redfs.h>
|
||||
#include <redtestutils.h>
|
||||
|
||||
|
||||
#define ISHEXDIGITU(c) (((c) >= 'A') && ((c) <= 'F'))
|
||||
#define ISHEXDIGITL(c) (((c) >= 'a') && ((c) <= 'f'))
|
||||
#define ISHEXDIGIT(c) (ISHEXDIGITL(c) || ISHEXDIGITU(c))
|
||||
|
||||
|
||||
/** @brief Converts an ASCII number into an int32_t.
|
||||
|
||||
Converts all decimal digit numbers up to the end of the string or to the
|
||||
first non-numerical character.
|
||||
|
||||
@note This function does *not* ignore leading white space.
|
||||
|
||||
@param pszNum Pointer to a constant array of characters.
|
||||
|
||||
@return The integer represented in the string.
|
||||
*/
|
||||
int32_t RedAtoI(
|
||||
const char *pszNum)
|
||||
{
|
||||
int32_t lValue = 0;
|
||||
int32_t lNegative = 1;
|
||||
uint32_t ulIdx = 0U;
|
||||
|
||||
if(pszNum[ulIdx] == '+')
|
||||
{
|
||||
ulIdx++;
|
||||
}
|
||||
else if(pszNum[ulIdx] == '-')
|
||||
{
|
||||
ulIdx++;
|
||||
lNegative = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No sign, implicitly positive.
|
||||
*/
|
||||
}
|
||||
|
||||
while(ISDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
lValue *= 10;
|
||||
lValue += pszNum[ulIdx] - '0';
|
||||
ulIdx++;
|
||||
}
|
||||
|
||||
lValue *= lNegative;
|
||||
|
||||
return lValue;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Convert a hexadecimal ASCII number into a uint32_t value.
|
||||
|
||||
The function processes all hex digits up to a NUL-terminator, or to the
|
||||
first non-hex character. Only hexadecimal digits are processed, so leading
|
||||
white space, or a leading "0x" prefix are not allowed.
|
||||
|
||||
If pachNum points to an empty string (points to a NUL), this function will
|
||||
return NULL, and the value at *pulNum will not be modified.
|
||||
|
||||
@note This function does not check for overflow. If there are more
|
||||
significant digits than can be represented in a uint32_t variable, the
|
||||
output is unspecified.
|
||||
|
||||
@param pszNum A pointer to a constant array of hex characters.
|
||||
@param pulNum A pointer to the location in which to store the uint32_t
|
||||
result. Upon return, this value will be modified ONLY if
|
||||
the function succeeds and the returned pointer is valid (not
|
||||
NULL).
|
||||
|
||||
@return A pointer to the byte following the converted number or NULL to
|
||||
indicate failure.
|
||||
*/
|
||||
const char *RedHtoUL(
|
||||
const char *pszNum,
|
||||
uint32_t *pulNum)
|
||||
{
|
||||
uint64_t ullValue;
|
||||
const char *pszReturn;
|
||||
|
||||
pszReturn = RedHtoULL(pszNum, &ullValue);
|
||||
if(pszReturn != NULL)
|
||||
{
|
||||
if(ullValue < UINT32_MAX)
|
||||
{
|
||||
*pulNum = (uint32_t)ullValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pszReturn;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Convert a hexadecimal ASCII number into a D_UINT64 value.
|
||||
|
||||
The function processes all hex digits up to a NUL-terminator, or to the
|
||||
first non-hex character. Only hexadecimal digits are processed, so leading
|
||||
white space, or a leading "0x" prefix are not allowed.
|
||||
|
||||
If pachNum points to an empty string (points to a NUL), this function will
|
||||
return NULL, and the value at *pulNum will not be modified.
|
||||
|
||||
@note This function does not check for overflow. If there are more
|
||||
significant digits than can be represented in a uint64_t variable, the
|
||||
output is unspecified.
|
||||
|
||||
@param pszNum A pointer to a constant array of hex characters.
|
||||
@param pullNum A pointer to the location in which to store the uint64_t
|
||||
result. Upon return, this value will be modified ONLY if
|
||||
the function succeeds and the returned pointer is valid (not
|
||||
NULL).
|
||||
|
||||
@return A pointer to the byte following the converted number, or NULL to
|
||||
indicate failure.
|
||||
*/
|
||||
const char *RedHtoULL(
|
||||
const char *pszNum,
|
||||
uint64_t *pullNum)
|
||||
{
|
||||
uint64_t ullValue = 0U;
|
||||
const char *pszReturn = NULL;
|
||||
uint32_t ulIdx = 0U;
|
||||
|
||||
REDASSERT(pszNum != NULL);
|
||||
REDASSERT(pullNum != NULL);
|
||||
|
||||
while(pszNum[ulIdx] != '\0')
|
||||
{
|
||||
char cDigit = pszNum[ulIdx];
|
||||
|
||||
if(ISDIGIT(cDigit))
|
||||
{
|
||||
cDigit -= '0';
|
||||
}
|
||||
else if(ISHEXDIGITU(cDigit))
|
||||
{
|
||||
cDigit -= ('A' - 10);
|
||||
}
|
||||
else if(ISHEXDIGITL(cDigit))
|
||||
{
|
||||
cDigit -= ('a' - 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
REDASSERT((ullValue & UINT64_SUFFIX(0xF000000000000000)) == 0U);
|
||||
|
||||
ullValue <<= 4U;
|
||||
ullValue += cDigit;
|
||||
|
||||
ulIdx++;
|
||||
pszReturn = &pszNum[ulIdx];
|
||||
}
|
||||
|
||||
/* Modify the number returned only if we found one or more valid hex
|
||||
digits.
|
||||
*/
|
||||
if(pszReturn != NULL)
|
||||
{
|
||||
*pullNum = ullValue;
|
||||
}
|
||||
|
||||
return pszReturn;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Convert the ASCII number to a uint32_t value.
|
||||
|
||||
The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
|
||||
they may be upper or lower case. The conversion process will stop with the
|
||||
first non hex or decimal digit.
|
||||
|
||||
If the number is negative (the first character is a '-' sign), the value
|
||||
will be range checked and returned as the equivalent unsigned value.
|
||||
|
||||
@note This function will NOT fail for numbers which exceed the size of a
|
||||
uint32_t value.
|
||||
|
||||
@param pszNum A pointer to the ASCII number to convert
|
||||
@param pulNum A pointer to the uint32_t location to store the result.
|
||||
This value will be modified on return only if the function
|
||||
succeeds and the returned pointer is valid (not NULL).
|
||||
|
||||
@return A pointer to the byte following the converted number, or NULL to
|
||||
indicate failure.
|
||||
*/
|
||||
const char *RedNtoUL(
|
||||
const char *pszNum,
|
||||
uint32_t *pulNum)
|
||||
{
|
||||
bool fNegative = false;
|
||||
uint32_t ulIdx = 0U;
|
||||
const char *pszReturn;
|
||||
|
||||
REDASSERT(pszNum != NULL);
|
||||
REDASSERT(pulNum != NULL);
|
||||
|
||||
if(pszNum[ulIdx] == '-')
|
||||
{
|
||||
fNegative = true;
|
||||
ulIdx++;
|
||||
}
|
||||
|
||||
/* Hex numbers must be prefixed with '0x'.
|
||||
*/
|
||||
if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
|
||||
{
|
||||
ulIdx += 2U;
|
||||
|
||||
if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
pszReturn = RedHtoUL(&pszNum[ulIdx], pulNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
}
|
||||
else if(ISDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
uint32_t ulTemp;
|
||||
|
||||
ulTemp = RedAtoI(&pszNum[ulIdx]);
|
||||
|
||||
while(ISDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
ulIdx++;
|
||||
}
|
||||
|
||||
if(fNegative)
|
||||
{
|
||||
/* Fail if the number is out of range.
|
||||
*/
|
||||
if(ulTemp > INT32_MAX)
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pulNum = -((int32_t)ulTemp);
|
||||
pszReturn = &pszNum[ulIdx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pulNum = ulTemp;
|
||||
pszReturn = &pszNum[ulIdx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return an error if there is not at least one hex or decimal digit.
|
||||
*/
|
||||
pszReturn = NULL;
|
||||
}
|
||||
|
||||
return pszReturn;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Convert the ASCII number pointed to by pachNum to a uint64_t value.
|
||||
|
||||
The number may be hex or decimal. Hex numbers must be prefixed by '0x', and
|
||||
they may be upper or lower case. The conversion process will stop with the
|
||||
first non hex or decimal digit.
|
||||
|
||||
If the number is negative (the first character is a '-' sign), the value
|
||||
will be range checked and returned as the equivalent unsigned value.
|
||||
|
||||
@param pszNum A pointer to the ASCII number to convert.
|
||||
@param pullNum A pointer to the uint64_t location to store the result.
|
||||
This value will be modified on return only if the function
|
||||
succeeds and the returned pointer is valid (not NULL).
|
||||
|
||||
@return A pointer to the byte following the converted number, or NULL to
|
||||
indicate failure.
|
||||
*/
|
||||
const char *RedNtoULL(
|
||||
const char *pszNum,
|
||||
uint64_t *pullNum)
|
||||
{
|
||||
bool fNegative = false;
|
||||
uint32_t ulIdx = 0U;
|
||||
const char *pszReturn;
|
||||
|
||||
REDASSERT(pszNum != NULL);
|
||||
REDASSERT(pullNum != NULL);
|
||||
|
||||
if(pszNum[ulIdx] == '-')
|
||||
{
|
||||
fNegative = true;
|
||||
ulIdx++;
|
||||
}
|
||||
|
||||
/* Hex numbers must be prefixed with '0x'.
|
||||
*/
|
||||
if((pszNum[ulIdx] == '0') && ((pszNum[ulIdx + 1U] == 'x') || (pszNum[ulIdx + 1U] == 'X')))
|
||||
{
|
||||
ulIdx += 2U;
|
||||
|
||||
if(ISDIGIT(pszNum[ulIdx]) || ISHEXDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
pszReturn = RedHtoULL(&pszNum[ulIdx], pullNum);
|
||||
}
|
||||
else
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
}
|
||||
else if(ISDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
uint64_t ullTemp = 0U;
|
||||
|
||||
while(ISDIGIT(pszNum[ulIdx]))
|
||||
{
|
||||
ullTemp *= 10U;
|
||||
ullTemp += pszNum[ulIdx] - '0';
|
||||
ulIdx++;
|
||||
}
|
||||
|
||||
if(fNegative)
|
||||
{
|
||||
/* Fail if the number is out of range.
|
||||
*/
|
||||
if(ullTemp > INT64_MAX)
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pullNum = (uint64_t)(-((int64_t)ullTemp));
|
||||
pszReturn = &pszNum[ulIdx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*pullNum = ullTemp;
|
||||
pszReturn = &pszNum[ulIdx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Return an error if there is not at least one hex or decimal digit.
|
||||
*/
|
||||
pszReturn = NULL;
|
||||
}
|
||||
|
||||
return pszReturn;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Convert an ASCII hex or decimal number, which may may have a "B",
|
||||
"KB", or "MB" suffix (case insensitive), to a binary value.
|
||||
|
||||
Hex numbers must be prefixed with "0x".
|
||||
|
||||
@note If there is no postfix, KB is assumed!
|
||||
|
||||
May fail due to bad formatting or overflow.
|
||||
|
||||
@param pszNum A pointer to the ASCII number to convert.
|
||||
@param pulResult A pointer to a uint32_t in which to place the result.
|
||||
|
||||
@return A pointer to the byte following the string, or NULL to indicate an
|
||||
error. In the event of an error, *pulResult will not be modified.
|
||||
*/
|
||||
const char *RedSizeToUL(
|
||||
const char *pszNum,
|
||||
uint32_t *pulResult)
|
||||
{
|
||||
uint32_t ulResult;
|
||||
const char *pszSuffix;
|
||||
const char *pszReturn;
|
||||
uint32_t ulIdx = 0U;
|
||||
|
||||
REDASSERT(pszNum != NULL);
|
||||
REDASSERT(pulResult != NULL);
|
||||
|
||||
/* Do the basic hex/decimal conversion
|
||||
*/
|
||||
pszSuffix = RedNtoUL(pszNum, &ulResult);
|
||||
if(pszSuffix != NULL)
|
||||
{
|
||||
if((pszSuffix[ulIdx] == 'B') || (pszSuffix[ulIdx] == 'b'))
|
||||
{
|
||||
ulIdx++;
|
||||
pszReturn = &pszSuffix[ulIdx];
|
||||
}
|
||||
else if( ((pszSuffix[ulIdx] == 'M') || (pszSuffix[ulIdx] == 'm'))
|
||||
&& ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
|
||||
{
|
||||
ulIdx += 2U;
|
||||
|
||||
if(ulResult > (UINT32_MAX / (1024U * 1024U)))
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulResult *= 1024U * 1024U;
|
||||
pszReturn = &pszSuffix[ulIdx];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The number is either postfixed with "KB" or something
|
||||
else (we don't care), but we must increment the pointer
|
||||
if it is something recognize.
|
||||
*/
|
||||
if( ((pszSuffix[ulIdx] == 'K') || (pszSuffix[ulIdx] == 'k'))
|
||||
&& ((pszSuffix[ulIdx + 1U] == 'B') || (pszSuffix[ulIdx + 1U] == 'b')))
|
||||
{
|
||||
ulIdx += 2U;
|
||||
}
|
||||
|
||||
/* "B" or "MB" were not specified, so it must be "KB"
|
||||
*/
|
||||
if(ulResult > (UINT32_MAX / 1024U))
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ulResult *= 1024UL;
|
||||
pszReturn = &pszSuffix[ulIdx];
|
||||
}
|
||||
}
|
||||
|
||||
if(pszReturn != NULL)
|
||||
{
|
||||
*pulResult = ulResult;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pszReturn = NULL;
|
||||
}
|
||||
|
||||
return pszReturn;
|
||||
}
|
||||
|
@ -0,0 +1,641 @@
|
||||
/* ----> 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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,159 @@
|
||||
/* ----> 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 a random number generator.
|
||||
*/
|
||||
#include <redfs.h>
|
||||
#include <redtestutils.h>
|
||||
|
||||
|
||||
/* This is the global seed used by the random number generator when the caller
|
||||
has not provided a seed to either the RedRand32() or RedRand64() functions.
|
||||
*/
|
||||
static uint64_t ullGlobalRandomNumberSeed;
|
||||
|
||||
/* Whether the above seed has been initialized.
|
||||
*/
|
||||
static bool fGlobalSeedInited;
|
||||
|
||||
|
||||
/** @brief Set the global seed used by the random number generator.
|
||||
|
||||
The global seed gets used when RedRand64() or RedRand32() are called with
|
||||
a NULL seed argument.
|
||||
|
||||
@param ullSeed The value to use as the global RNG seed.
|
||||
*/
|
||||
void RedRandSeed(
|
||||
uint64_t ullSeed)
|
||||
{
|
||||
ullGlobalRandomNumberSeed = ullSeed;
|
||||
fGlobalSeedInited = true;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Generate a 64-bit pseudo-random number.
|
||||
|
||||
The period of this random number generator is 2^64 (1.8 x 1019). These
|
||||
parameters are the same as the default one-stream SPRNG lcg64 generator and
|
||||
it satisfies the requirements for a maximal period.
|
||||
|
||||
The tempering value is used and an AND mask and is specifically selected to
|
||||
favor the distribution of lower bits.
|
||||
|
||||
@param pullSeed A pointer to the seed to use. Set this value to NULL to
|
||||
use the internal global seed value.
|
||||
|
||||
@return A pseudo-random number in the range [0, UINT64_MAX].
|
||||
*/
|
||||
uint64_t RedRand64(
|
||||
uint64_t *pullSeed)
|
||||
{
|
||||
const uint64_t ullA = UINT64_SUFFIX(2862933555777941757);
|
||||
const uint64_t ullC = UINT64_SUFFIX(3037000493);
|
||||
const uint64_t ullT = UINT64_SUFFIX(4921441182957829599);
|
||||
uint64_t ullN;
|
||||
uint64_t *pullSeedPtr;
|
||||
uint64_t ullLocalSeed;
|
||||
|
||||
if(pullSeed != NULL)
|
||||
{
|
||||
ullLocalSeed = *pullSeed;
|
||||
pullSeedPtr = pullSeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!fGlobalSeedInited)
|
||||
{
|
||||
/* Unfortunately, the Reliance Edge OS services don't give us much
|
||||
to work with to initialize the global seed. There is no entropy
|
||||
abstraction, no tick count abstraction, and the timestamp
|
||||
abstraction uses an opaque type which is not guaranteed to be an
|
||||
integer. The best we can do is use the RTC.
|
||||
|
||||
Tests using the RNG should be supplying a seed anyway, for
|
||||
reproducibility.
|
||||
*/
|
||||
RedRandSeed((uint64_t)RedOsClockGetTime());
|
||||
}
|
||||
|
||||
ullLocalSeed = ullGlobalRandomNumberSeed;
|
||||
pullSeedPtr = &ullGlobalRandomNumberSeed;
|
||||
}
|
||||
|
||||
ullN = (ullLocalSeed * ullA) + ullC;
|
||||
|
||||
*pullSeedPtr = ullN;
|
||||
|
||||
/* The linear congruential generator used above produces good psuedo-random
|
||||
64-bit number sequences, however, as with any LCG, the period of the
|
||||
lower order bits is much shorter resulting in alternately odd/even pairs
|
||||
in bit zero.
|
||||
|
||||
The result of the LGC above is tempered below with a series of XOR and
|
||||
shift operations to produce a more acceptable equidistribution of bits
|
||||
throughout the 64-bit range.
|
||||
*/
|
||||
ullN ^= (ullN >> 21U) & ullT;
|
||||
ullN ^= (ullN >> 43U) & ullT;
|
||||
ullN ^= (ullN << 23U) & ~ullT;
|
||||
ullN ^= (ullN << 31U) & ~ullT;
|
||||
|
||||
return ullN;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Generate a 32-bit pseudo-random number.
|
||||
|
||||
@note The 32-bit random number generator internally uses the 64-bit random
|
||||
number generator, returning the low 32-bits of the pseudo-random
|
||||
64-bit value.
|
||||
|
||||
@param pulSeed A pointer to the seed to use. Set this value to NULL to use
|
||||
the internal global seed value.
|
||||
|
||||
@return A pseudo-random number in the range [0, UINT32_MAX].
|
||||
*/
|
||||
uint32_t RedRand32(
|
||||
uint32_t *pulSeed)
|
||||
{
|
||||
uint64_t ullN;
|
||||
|
||||
if(pulSeed != NULL)
|
||||
{
|
||||
uint64_t ullLocalSeed;
|
||||
|
||||
ullLocalSeed = *pulSeed;
|
||||
ullN = RedRand64(&ullLocalSeed);
|
||||
*pulSeed = (uint32_t)ullLocalSeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
ullN = RedRand64(NULL);
|
||||
}
|
||||
|
||||
return (uint32_t)ullN;
|
||||
}
|
||||
|
Reference in New Issue
Block a user