/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include <stdlib.h>
#include <misc/multiply.h>
#include <blc_stdlib.h>

/****************************************************************************/
/*							Explanation										*/
/****************************************************************************/

/*
*	Get an integer x so that it is less than 1E9. If we now divide this
*	number by 1E9 using infinite precision float division, then we get
*	a number where the integer part of the float point result is 0.
*	Then we can convert the number to a string by multiplying the float
*	by 10 in a loop. After each multiply the next digit will be the
*	integer part, that we write into the string and then discard it,
*	keeping the number less than 1.0 all the time. Since 1E9 - 1 has at
*	most 9 decimal digits, we have to execute the loop exactly 9 times.
*
*	The above algorithm works, but it has a huge drawback: it's based on
*	infinite precision float division. We don't like division and we
*	prefer positive integers over floats. So, we have to do a few twists.
*
*	Instead of dividing by 1E9 we would of course rather multiply by
*	1E-9. Alas, 1E-9 is an infinite binary sequence. However, if we
*	ignore the bits after the first 60, we introduce a relative error
*	of 0.606847.. * 2^-60. During the conversion we will also multiply
*	that error by 1E9. Since our conversion method always rounds down
*	(i.e. 1.99999... is rounded to 1.0) we will underestimate
*	the number. By how much? Well, if the error is anything but 0,
*	we definitely will generate a result string that is 1 less than
*	the number to convert, but if the number is large enough, we might
*	introduce an error that is > 1, thus generating a string less than
*	the number by 2 or more. So where is the limit? Since the accumulated
*	error will be e = x * 0.606847... * 2^-60 * 1E9, we have to find x where
*	the error reaches 1.0. It is 1.899855398E9, a number larger than our 1E9
*	limit. Therefore, if we are converting numbers between 1E9 and 0 we
*	know that the resulting string will be exactly 1 less than the number
*	itself. We can easily compensate for that by adding 1 to the number
*	before the conversion (if f(x) = x-1, then f(x+1) = x).
*
*	The above allowed us to limit the precision of the float representation
*	of 1E-9 to 60 bits but it is still a float point number. However, if we
*	multiply it by 2^60, we will get an integer (since we've already discarded
*	all fractional bits after the 60-th). This integer is 1152921504, that
*	happens to fit in 32 bits. (It is a 60-bit number but it fits in the
*	32-bit word because it had 29 0-s after the radix point that became
*	leading 0-s on the integer). Thus, the initial float division by 1E9 can
*	now be substituted with a 32x32=>64 bit integer multiply, an alltogether
*	much more microcontroller friendly proposition. Our radix point, due to
*	the 2^60 multiply, will be after the 4th bit (from the left) of the 64-bit
*	word. That is, the integer part is represented by the top 4 bits of the
*	word and the fraction is the lower 60 bits. That fact makes the extraction
*	of digits very easy on a processor with a barrel shifter, such as the ARM.
*
*	Only one problem remains. The above algorithm is limited to numbers
*	between 0 and 1E9-1. Since the largest 32 bit unsigned number is
*	4.294967295E9, by processing a single decimal digit (that is less
*	than 5) separately, we can assure that the remaining number is
*	always less that 1E9. Processing the >= 1E9 bit is easy, we simply
*	execute the first 3 steps of a binary division (i.e. 3 compare and
*	subtract steps).
*/

/****************************************************************************/
/*					User API functions										*/
/****************************************************************************/

/** @addtogroup stdlib */
/**	@{ */

/**
*	Converts a 32-bit unsigned integer to ASCII in radix 10.
*
*	The number will be converted without leading zeroes or spaces and the
*	result is terminated by a NUL byte.
*
*	@param	numb	The unsigned integer to convert
*	@param	buff	Pointer to the buffer where the result is stored.
*					At worst case the buffer needs to be 11 bytes long.
*
*	@return			The length of the final string, not counting the
*					terminating NUL.
*
*	@note	This function is not a standard C library function.
*/

int		ultostr10( char *buff, unsigned long numb )
{
	return( _blc_itoa10( buff, numb, 0 ) );
}

/** @} */

/****************************************************************************/
/*					Internal interface										*/
/****************************************************************************/

/*
*	Converts a 32-bit unsigned integer to ASCII in radix 10.
*
*	The number will be converted with or without leading zeroes and the
*	result is terminated by a 0 byte.
*
*	buf		Pointer to the buffer where the result is stored.
*			At worst case the buffer needs to be 11 bytes long.
*
*	num		The unsigned integer to convert
*
*	ldz		If 0, no leading zeroes are added. If !0, then leading
*			zeroes are added and the result is always 10 characters.
*
*	Returns	the length of the final string, not counting the
*	terminating 0.
*/

int		_blc_itoa10( char *buf, unsigned long num, int ldz )
{
unsigned int		dig;
unsigned int		len;
unsigned long long	acc;

	if (  num < 10 ) {

		// Although the algorithm works for 0, we treat the single digit
		// case as special, for speed resons. As single digit conversions
		// are reasonably frequent, the extra code is worth it.

		for ( len = 0 ; ++len < 10 && ldz ; ) *buf++ = '0';
		*buf++ = num + '0';
		*buf = '\0';
		return( len );
	}

	len = 1000000000u;
	dig = 0;

	if ( num >= len ) {

		// The number is larger than our conversion limit, process the 1E9
		// and above bits. We do the first few steps of an unrolled division
		// by 1E9.

		len <<= 2;

		if ( num >= len ) {

			// The number is 4E9 or larger. We know that this is the
			// only component, no need to check for 2E9 or 1E9.

			num -= len;
			dig  = 4;
		}
		else {

			// 1E9 <= number < 4E9. Thus, we check for 2E9 and 1E9.

			len >>= 1;

			if ( num >= len ) {

				num -= len;
				dig  = 2;
			}

			len >>= 1;

			if ( num >= len ) {

				num -= len;
				dig++;
			}
		}

		// At this point the remainder of the division is in num while the
		// quotient is in dig. Write the first digit into the buffer.

		*buf++ = dig + '0';
		len = 1;
	}
	else {

		// The number is less than 1E9. If we need to produce leading
		// zeroes, we need to emit a '0' for the 1E9 digit.

		len = 0;

		if ( ldz ) {

			*buf++ = '0';
			len = 1;
		}
	}

	// We know that now num is between 999999999 and 0, inclusive.
	// Do the multiply with 1E-9 * 2^60 and compensate for the error.

	acc = umul32x32_64( 0x44b82fa0, num + 1 );

	// The result is now in the lower 60 bits of the 64-bit word, as a
	// fractional number. Extract the 9 digits.

	for ( num = 10 ; --num ; ) {

		acc = umul64x32_64( acc, 10 );
		dig = acc >> 60;
		acc = acc & ( -1ull >> 4 );	// This should be 1 insn, gcc makes it 4...

		if ( dig || len ) {

			*buf++ = dig + '0';
			len++;
		}
	}

	*buf = 0;
	return( len );
}

