/*
* Copyright (c) 2015 Jiri Svoboda
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** @addtogroup libc
* @{
*/
/**
* @file Integer mathematical functions
*/
#include <errno.h>
#include <imath.h>
#include <stdbool.h>
#include <stdint.h>
/** Compute integer power of 10, unsigned 64-bit result.
*
* Fast algorithm using binary digits of exp to compute 10^exp in
* time O(log exp).
*
* @param exp Exponent
* @param res Place to store result
* @return EOK on success, ERANGE if result does not fit into result type
*/
errno_t ipow10_u64(unsigned exp, uint64_t *res)
{
uint64_t a;
uint64_t r;
r = 1;
a = 10;
while (true) {
if ((exp & 1) != 0) {
if ((r * a) / a != r)
return ERANGE;
r = r * a;
}
exp = exp >> 1;
if (exp == 0)
break;
if ((a * a) / a != a)
return ERANGE;
a = a * a;
}
*res = r;
return EOK;
}
/** Compute integer base 10 logarithm, unsigned 64-bit argument.
*
* For integer v, compute floor(log_10 v). Fast algorithm computing
* the binary digits of the result r in time O(log r).
*
* @param v Value to compute logarithm from
* @return Logarithm value
*/
unsigned ilog10_u64(uint64_t v)
{
unsigned b;
unsigned e;
uint64_t p10p2[6];
uint64_t a;
unsigned r;
/* Determine largest b such that 10^2^b <= v */
b = 0;
e = 1;
a = 10;
p10p2[0] = a;
while (v / a >= a) {
++b;
a = a * a;
e = e + e;
p10p2[b] = a;
}
/* Determine the binary digits of largest e such that 10^e <= v */
r = 0;
while (true) {
if (v >= p10p2[b]) {
v = v / p10p2[b];
r = r ^ (1 << b);
}
if (b == 0)
break;
--b;
}
return r;
}
/** @}
*/