PROWAREtech

articles » current » c-plus-plus » implement-std-cin-and-std-cout

C++: How to Implement std::cin and std::cout

It is easy to implement a mock version of the C++ library std::cin, std::cout and std::string.

This code relies upon the custom String class which has been slightly modified for the following code.

The C++ std::cout and std::cin are very valuable additions to the C++ library. Every wonder how they did it? Implement the std::cout and std::cin classes with your own code and greatly reduce the size of your executable.

This code is a lightweight version of the official C++ version. If all the features of std::cout and std::cin are required then use the version included with C++, otherwise, it is possible to work the same with strings and numbers using this little library.

This code should compile on Linux 64-bit, and Windows 32- and 64-bit.

Doesn't it look the same? It is implemented totally differently.


// main.cpp
#include "console.h"
using namespace std;

int main()
{
	string str = "abc";
	cout << str;
	str += "def";
	cout << str << endl;
	string str2 = str;
	if (str == str2)
		cout << str << " equal to " << str2 << endl;
	if (str != "bcdef")
		cout << str << " not equal to bcdef" << endl;
	if (str > 'a')
		cout << str << " greater than 'a'" << endl;
	cout << str2 << endl;
	str += str2;
	cout << str << endl;
	str += ' ';
	str += 3.1415926535897931; // numbers are converted to strings
	cout << str << endl;
	str2 = 2333222111;
	cout << str2 << endl;
	cout << (str2 >> 4) << endl; // returns 222111 (str2 starting at character index 4)
	str2 = str2 >> 1; // str2 equals itself starting at character index 1
	cout << str2 << endl;
	str2 += -776655;
	cout << str2 << endl;

	double dbl;
	long long i;
	while (1)
	{
		cout << "Enter a floating-point number (0 to end): ";
		cin >> dbl;
		if (!dbl)
			break;
		cout << dbl << endl;
		cout << "Enter an integer (0 to end): ";
		cin >> i;
		if (!i)
			break;
		cout << i << endl;
	}
	return 0;
}

Here is the main header file to include.


// console.h
#ifndef CONSOLE_H
#define CONSOLE_H

#if defined WIN32 || _WIN64
#include <windows.h>
#include "string.h"

void write_to_console(const char* sz, unsigned long len)
{
	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
	if (h != INVALID_HANDLE_VALUE)
		WriteConsoleA(h, sz, len, &len, NULL);
}

void read_from_console(std::string& str)
{
	char sz[16384];
	unsigned long ul;
	HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
	if (h != INVALID_HANDLE_VALUE)
		if (ReadConsoleA(h, (LPVOID)sz, 16384, &ul, NULL))
			str = sz;
}

template <typename T> void read_from_console(T& t)
{
	char sz[16384];
	unsigned long ul;
	HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
	if (h != INVALID_HANDLE_VALUE)
		if (ReadConsoleA(h, (LPVOID)sz, 16384, &ul, NULL))
			string_to_number(sz, t);
}

#else // LINUX64

#include <stdio.h>

void write_to_console(const char* sz, unsigned long len)
{
	puts(sz);
}

void read_from_console(std::string& str)
{
	char sz[16384];
	gets(sz);
	str = sz;
}

template <typename T> void read_from_console(T& t)
{
	char sz[16384];
	gets(sz);
	string_to_number(sz, t);
}

#endif

namespace std
{
	const char endl = '\n';
	enum out
	{
		cout
	};
	enum in
	{
		cin
	};
}

void operator>>(std::in cin, std::string& s)
{
	read_from_console(s);
}

template <typename T> void operator>>(std::in cin, T& t)
{
	read_from_console(t);
}

const std::out operator<<(std::out cout, const std::string& s)
{
	write_to_console(*s, s.length());
	return cout;
}

template <typename T> const std::out operator<<(std::out cout, const T t)
{
	std::string s = t;
	write_to_console(*s, s.length());
	return cout;
}

#endif

// common.h
#ifndef COMMON_H
#define COMMON_H

void number_to_string(unsigned long long number, char* buffer, const unsigned int negative)
{
	if (negative)
	{
		*buffer++ = '-';
		number = (unsigned long long)(-(long long)number);
	}
	char* first = buffer;
	do
	{
		unsigned digit = (unsigned)(number % 10);
		number /= 10;
		*buffer++ = (char)(digit + '0');
	} while (number > 0);
	*buffer-- = '\0';
	do
	{
		char temp = *buffer;
		*buffer = *first;
		*first = temp;
		--buffer;
		++first;
	} while (first < buffer);
}

template <typename T> void string_to_number(const char* sz, T& t)
{
	int c; // ascii char
	T w = 0;
	int sign;

	// skip whitespace
	while (*sz == ' ' || (*sz == '\n') | (*sz == '\r') | (*sz == '\t'))
		++sz;

	c = (int)(unsigned char)*sz++;
	sign = c; // save sign
	if (c == '-' || c == '+')
		c = (int)(unsigned char)*sz++;

	while ((c >= '0') & (c <= '9'))
	{
		w = 10 * w + (c - (int)'0'); // radix == 10
		c = (int)(unsigned char)*sz++;
	}

	if (sign == '-')
		t = -w;
	else
		t = w;
}

double power_base_10(int y)
{
	int ret = 1;
	for (int i = 0; i < y; i++)
		ret *= 10;
	return ret;
}

void string_to_number(const char* sz, double& dbl)
{
	int c; // ascii char
	long long w = 0;
	unsigned long long f = 0;
	int sign;

	// skip whitespace
	while (*sz == ' ' || (*sz == '\n') | (*sz == '\r') | (*sz == '\t'))
		++sz;

	c = (int)(unsigned char)*sz++;
	sign = c; // save sign
	if (c == '-' || c == '+')
		c = (int)(unsigned char)*sz++;

	int period = 0;

	while ((c >= '0') & (c <= '9') || c == '.')
	{
		if (period)
		{
			if (c == '.')
				break;
			period++;
			f = 10 * f + (c - (int)'0'); // radix == 10
		}
		else
		{
			if (c == '.')
				period = 1;
			else
				w = 10 * w + (c - (int)'0'); // radix == 10
		}
		c = (int)(unsigned char)*sz++;
	}

	if (period)
		dbl = (sign == '-' ? -1 : 1) * w + f / power_base_10(period - 1);
	else
	{
		if (sign == '-')
			dbl = -w;
		else
			dbl = w;
	}
}

#endif

This is the modified string class header file.


// string.h
#include "common.h"
#include "strfloat.h"

#ifndef STRING_H
#define STRING_H

namespace std
{
	void copy_16bit(char* dest, const char* source, const unsigned int length)
	{
		unsigned int limit = length >> 1 << 1; // 2^1 is 2
		unsigned int i;
		for (i = 0; i < limit; i += sizeof(void*) / sizeof(char)) // 2 bytes divided by 1 or 2
			*((short*)(dest + i)) = *((short*)(source + i)); // there is no benefit if copying UNICODE string on 16 bit system, but UNICODE is rare for a 16-bit system
		for (; i < length; i++)
			dest[i] = source[i];
		dest[i] = '\0';
	}

	void copy_32bit(char* dest, const char* source, const unsigned int length)
	{
		unsigned int limit = length >> 2 << 2; // 2^2 is 4
		unsigned int i;
		for (i = 0; i < limit; i += sizeof(void*) / sizeof(char)) // 4 bytes divided by 1 or 2
			*((int*)(dest + i)) = *((int*)(source + i));
		for (; i < length; i++)
			dest[i] = source[i];
		dest[i] = '\0';
	}

	void copy_64bit(char* dest, const char* source, const unsigned int length)
	{
		unsigned int limit = length >> 3 << 3; // 2^3 is 8
		unsigned int i;
		for (i = 0; i < limit; i += sizeof(void*) / sizeof(char)) // 8 bytes divided by 1 or 2
			*((long long*)(dest + i)) = *((long long*)(source + i));
		for (; i < length; i++)
			dest[i] = source[i];
		dest[i] = '\0';
	}

	template <typename T> void float_to_string(T number, char* dest)
	{
		dragon4::Options* opt = new dragon4::Options;
		opt->cutoff_mode = dragon4::CutoffMode_TotalLength;
		opt->digits_left = -1;
		opt->digits_right = -1;
		opt->digit_mode = dragon4::DigitMode_Unique;
		opt->exp_digits = -1;
		opt->min_digits = -1;
		opt->precision = -1;
		opt->scientific = (number < 0.0000000000000001 || number >= 100000000000000000.0);
		opt->sign = 0;
		opt->trim_mode = dragon4::TrimMode_DptZeros;
		dragon4::Scratch* scratch = new dragon4::Scratch;
		PrintFloat_IEEE_binary(scratch, number, opt);
		int i;
		for (i = 0; scratch->repr[i]; i++)
			dest[i] = scratch->repr[i];
		dest[i] = '\0';
		delete scratch;
		scratch = nullptr;
		delete opt;
		opt = nullptr;
	}

	class StringData
	{
	public:
		char* array;
		unsigned int max_size;
		unsigned int length;
		void(*copy_string)(char* dest, const char* source, const unsigned int length);
		StringData(unsigned int buffer_size) : length(0), max_size(buffer_size)
		{
			copy_string = (sizeof(void*) == 8 ? copy_64bit : (sizeof(void*) == 4 ? copy_32bit : copy_16bit));
			array = new char[max_size];
			array[0] = '\0';
		}
		~StringData()
		{
			delete[]array;
			array = nullptr;
		}
	};

	class string
	{
	private:
		StringData* sd;

	public:
		static unsigned long strlen(const char* sz)
		{
			unsigned long i = 0;
			while (sz[i])
				i++;
			return i;
		}

		string()
		{
			sd = new StringData(1024);
		}

		string(const float source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const double source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const long long source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const unsigned long long source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const long source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const unsigned long source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const int source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const unsigned int source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const char* source)
		{
			sd = new StringData(1024);
			this->operator=(source);
		}

		string(const string& obj)
		{
			sd = new StringData(obj.sd->max_size);
			this->operator=(obj);
		}

		string(const char ch)
		{
			sd = new StringData(1024);
			this->operator=(ch);
		}

		~string()
		{
			delete sd;
			sd = nullptr;
		}

		const char* c_string() const
		{
			return sd->array;
		}

		unsigned int length() const
		{
			return sd->length;
		}

		unsigned int buffer_size() const
		{
			return sd->max_size * sizeof(char);
		}

		unsigned int buffer_length() const
		{
			return sd->max_size;
		}

		const string& operator=(const string& obj)
		{
			if (this != &obj)
			{
				if (obj.sd->length >= sd->max_size) // then increase array size
				{
					sd->max_size = obj.sd->max_size;
					delete[]sd->array;
					sd->array = new char[sd->max_size];
				}
				sd->copy_string(sd->array, obj.sd->array, obj.sd->length);
				sd->length = obj.sd->length;
			}
			return (*this);
		}

		void operator+=(const string& obj)
		{
			if (obj.sd->length >= sd->max_size - sd->length) // then increase array size
			{
				sd->max_size = (obj.sd->length + sd->length) << 1; // give it a little bit of a buffer (2 times length of new string)
				char* new_array = new char[sd->max_size];
				sd->copy_string(new_array, sd->array, sd->length);
				delete[]sd->array;
				sd->array = new_array;
			}
			sd->copy_string(&sd->array[sd->length], obj.sd->array, obj.sd->length);
			sd->length += obj.sd->length;
		}

		void operator+=(const char* source)
		{
			unsigned int i, j;
			for (i = sd->length, j = 0; source[j]; )
			{
				sd->array[i++] = source[j++];
				if (i == sd->max_size) // then increase array size
				{
					sd->max_size += 1024;
					char* new_array = new char[sd->max_size];
					unsigned int x;
					for (x = 0; x < i; x++)
						new_array[x] = sd->array[x];
					new_array[x] = '\0';
					delete[]sd->array;
					sd->array = new_array;
				}
			}
			sd->array[i] = '\0';
			sd->length = i;
		}

		void operator+=(const char ch)
		{
			char sz[2] = { ch, '\0' };
			this->operator+=(sz);
		}

		const char* operator=(const char* source)
		{
			sd->length = 0;
			this->operator+=(source);
			return source;
		}

		char operator=(const char ch)
		{
			sd->length = 0;
			this->operator+=(ch);
			return ch;
		}


		double operator=(const float number)
		{
			char* sz = new char[sizeof(dragon4::Scratch::repr)];
			float_to_string(number, sz);
			this->operator=(sz);
			delete[]sz;
			sz = nullptr;
			return number;
		}

		void operator+=(const float number)
		{
			char* sz = new char[sizeof(dragon4::Scratch::repr)];
			float_to_string(number, sz);
			this->operator+=(sz);
			delete[]sz;
			sz = nullptr;
		}


		double operator=(const double number)
		{
			char* sz = new char[sizeof(dragon4::Scratch::repr)];
			float_to_string(number, sz);
			this->operator=(sz);
			delete[]sz;
			sz = nullptr;
			return number;
		}

		void operator+=(const double number)
		{
			char* sz = new char[sizeof(dragon4::Scratch::repr)];
			float_to_string(number, sz);
			this->operator+=(sz);
			delete[]sz;
			sz = nullptr;
		}


		long long operator=(const long long number)
		{
			char sz[32];
			number_to_string(number, sz, number < 0);
			this->operator=(sz);
			return number;
		}

		void operator+=(const long long number)
		{
			char sz[32];
			number_to_string(number, sz, number < 0);
			this->operator+=(sz);
		}

		unsigned long long operator=(const unsigned long long number)
		{
			char sz[32];
			number_to_string(number, sz, false);
			this->operator=(sz);
			return number;
		}

		void operator+=(const unsigned long long number)
		{
			char sz[32];
			number_to_string(number, sz, false);
			this->operator+=(sz);
		}



		int operator=(const int number)
		{
			this->operator=((long long)number);
			return number;
		}

		void operator+=(const int number)
		{
			this->operator+=((long long)number);
		}

		unsigned int operator=(const unsigned int number)
		{
			this->operator=((unsigned long long)number);
			return number;
		}

		void operator+=(const unsigned int number)
		{
			this->operator+=((unsigned long long)number);
		}



		long operator=(const long number)
		{
			this->operator=((long long)number);
			return number;
		}

		void operator+=(const long number)
		{
			this->operator+=((long long)number);
		}

		unsigned long operator=(const unsigned long number)
		{
			this->operator=((unsigned long long)number);
			return number;
		}

		void operator+=(const unsigned long number)
		{
			this->operator+=((unsigned long long)number);
		}



		bool operator==(const char* str) const
		{
			unsigned int i = 0;
			char* a = sd->array;
			for (i = 0; a[i] && str[i] && a[i] == str[i]; i++);
			return(a[i] == str[i]);
		}

		bool operator==(const string& obj) const
		{
			return this->operator==(obj.sd->array);
		}

		bool operator==(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return this->operator==(sz);
		}

		bool operator!=(const string& obj) const
		{
			return !this->operator==(obj.sd->array);
		}

		bool operator!=(const char* str) const
		{
			return !this->operator==(str);
		}

		bool operator!=(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return !this->operator==(sz);
		}

		bool operator>(const char* str) const
		{
			unsigned int i = 0;
			char* a = sd->array;
			for (i = 0; a[i] && str[i] && a[i] == str[i]; i++);
			return(a[i] > str[i]);
		}

		bool operator>(const string& obj) const
		{
			return this->operator>(obj.sd->array);
		}

		bool operator>(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return this->operator>(sz);
		}

		bool operator<(const char* str) const
		{
			unsigned int i = 0;
			char* a = sd->array;
			for (i = 0; a[i] && str[i] && a[i] == str[i]; i++);
			return(a[i] < str[i]);
		}

		bool operator<(const string& obj) const
		{
			return this->operator<(obj.sd->array);
		}

		bool operator<(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return this->operator<(sz);
		}

		bool operator>=(const char* str) const
		{
			unsigned int i = 0;
			char* a = sd->array;
			for (i = 0; a[i] && str[i] && a[i] == str[i]; i++);
			return(a[i] >= str[i]);
		}

		bool operator>=(const string& obj) const
		{
			return this->operator>=(obj.sd->array);
		}

		bool operator>=(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return this->operator>=(sz);
		}

		bool operator<=(const char* str) const
		{
			unsigned int i = 0;
			char* a = sd->array;
			for (i = 0; a[i] && str[i] && a[i] == str[i]; i++);
			return(a[i] <= str[i]);
		}

		bool operator<=(const string& obj) const
		{
			return this->operator<=(obj.sd->array);
		}

		bool operator<=(const char ch) const
		{
			char sz[2] = { ch, '\0' };
			return this->operator<=(sz);
		}

		char operator[](const unsigned int index) const // should enter an index value less than length(); length == '\0'
		{
			return sd->array[index];
		}

		const char* operator>>(const unsigned int index) // returns the string at the given index
		{
			if (index < sd->length)
				return &sd->array[index];
			return &sd->array[sd->length];
		}
	};

	const char* operator*(const string& obj)
	{
		return obj.c_string();
	}
}
#endif

The next two files deal exclusively with converting float and double data-types to strings.


// strfloat.h
#ifndef STRFLOAT_H
#define STRFLOAT_H

namespace dragon4
{
	typedef enum DigitMode
	{
		/* Round digits to print shortest uniquely identifiable number. */
		DigitMode_Unique,
		/* Output the digits of the number as if with infinite precision */
		DigitMode_Exact,
	} DigitMode;

	typedef enum CutoffMode
	{
		/* up to cutoffNumber significant digits */
		CutoffMode_TotalLength,
		/* up to cutoffNumber significant digits past the decimal point */
		CutoffMode_FractionLength,
	} CutoffMode;

	typedef enum TrimMode
	{
		TrimMode_None,         /* don't trim zeros, always leave a decimal point */
		TrimMode_LeaveOneZero, /* trim all but the zero before the decimal point */
		TrimMode_Zeros,        /* trim all trailing zeros, leave decimal point */
		TrimMode_DptZeros,     /* trim trailing zeros & trailing decimal point */
	} TrimMode;


	// * Options struct for easy passing of Dragon4 options.
	// *
	// *   scientific - boolean controlling whether scientific notation is used
	// *   digit_mode - whether to use unique or fixed fractional output
	// *   cutoff_mode - whether 'precision' refers to all digits, or digits past
	// *                 the decimal point.
	// *   precision - When negative, prints as many digits as needed for a unique
	// *               number. When positive specifies the maximum number of
	// *               significant digits to print.
	// *   sign - whether to always show sign
	// *   trim_mode - how to treat trailing 0s and '.'. See TrimMode comments.
	// *   digits_left - pad characters to left of decimal point. -1 for no padding
	// *   digits_right - pad characters to right of decimal point. -1 for no padding.
	// *                  Padding adds whitespace until there are the specified
	// *                  number characters to sides of decimal point. Applies after
	// *                  trim_mode characters were removed. If digits_right is
	// *                  positive and the decimal point was trimmed, decimal point
	// *                  will be replaced by a whitespace character.
	// *   exp_digits - Only affects scientific output. If positive, pads the
	// *                exponent with 0s until there are this many digits. If
	// *                negative, only use sufficient digits.
	typedef struct {
		int scientific;
		DigitMode digit_mode;
		CutoffMode cutoff_mode;
		int precision;
		int min_digits;
		int sign;
		TrimMode trim_mode;
		int digits_left;
		int digits_right;
		int exp_digits;
	} Options;


	const int c_BigInt_MaxBlocks = 511; /* or 1023 */

	typedef struct BigInt
	{
		unsigned int length;
		unsigned int blocks[c_BigInt_MaxBlocks];
	} BigInt;

	const int BIGINT_GROUPSIZE = 7;
	typedef struct {
		BigInt bigints[BIGINT_GROUPSIZE];
		char repr[4096];
	} Scratch;

	unsigned int PrintFloat_IEEE_binary(Scratch* scratch, const float value, const Options* opt);
	unsigned int PrintFloat_IEEE_binary(Scratch* scratch, const double& value, const Options* opt);

}
#endif

// strfloat.cpp
#include "strfloat.h"

#define CEIL(x) (int)((x <= 0.0) ? x : (((int)x < x) ? x : (x + 1)))
#define bitmask_u64(n) (unsigned long long)~(~0ULL << n)
#define bitmask_u32(n) (unsigned int)~(~0UL << n)

namespace dragon4
{
	void movemem(char* dest, const char* src, unsigned count)
	{
		char* temp = new char[count];
		for (unsigned i = 0; i < count; i++)
			temp[i] = src[i];
		for (unsigned i = 0; i < count; i++)
			dest[i] = temp[i];
		delete[]temp;
	}



	// *  Get the log base 2 of a 32-bit unsigned integer.
	// *  http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup
	// */
	static unsigned int LogBase2_32(unsigned int val)
	{
		static const unsigned char logTable[256] =
		{
			0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
			4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
			5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
			5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
			6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
			6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
			6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
			6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
			7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
		};

		unsigned int temp;

		temp = val >> 24;
		if (temp)
		{
			return 24 + logTable[temp];
		}

		temp = val >> 16;
		if (temp)
		{
			return 16 + logTable[temp];
		}

		temp = val >> 8;
		if (temp)
		{
			return 8 + logTable[temp];
		}

		return logTable[val];
	}

	static unsigned int LogBase2_64(unsigned long long val)
	{
		unsigned long long temp;

		temp = val >> 32;
		if (temp)
		{
			return 32 + LogBase2_32((unsigned int)temp);
		}

		return LogBase2_32((unsigned int)val);
	}

	/* Copy integer */
	static void BigInt_Copy(BigInt* dst, const BigInt* src)
	{
		unsigned int length = src->length;
		unsigned int* dstp = dst->blocks;
		const unsigned int* srcp;
		for (srcp = src->blocks; srcp != src->blocks + length; ++dstp, ++srcp)
		{
			*dstp = *srcp;
		}
		dst->length = length;
	}

	/* Basic type accessors */
	static void  BigInt_Set_uint64(BigInt* i, unsigned long long val)
	{
		if (val > bitmask_u64(32))
		{
			i->blocks[0] = val & bitmask_u64(32);
			i->blocks[1] = (val >> 32) & bitmask_u64(32);
			i->length = 2;
		}
		else if (val != 0)
		{
			i->blocks[0] = val & bitmask_u64(32);
			i->length = 1;
		}
		else
		{
			i->length = 0;
		}
	}

	static void BigInt_Set_uint32(BigInt* i, unsigned int val)
	{
		if (val != 0)
		{
			i->blocks[0] = val;
			i->length = 1;
		}
		else
		{
			i->length = 0;
		}
	}

	/* Returns 1 if the value is zero */
	static int BigInt_IsZero(const BigInt* i)
	{
		return i->length == 0;
	}

	/* Returns 1 if the value is even */
	static int BigInt_IsEven(const BigInt* i)
	{
		return (i->length == 0) || ((i->blocks[0] & 1) == 0);
	}

	/* Returns 0 if (lhs = rhs), negative if (lhs < rhs), positive if (lhs > rhs) */
	static int BigInt_Compare(const BigInt* lhs, const BigInt* rhs)
	{
		int i;

		/* A bigger length implies a bigger number. */
		int lengthDiff = lhs->length - rhs->length;
		if (lengthDiff != 0)
		{
			return lengthDiff;
		}

		/* Compare blocks one by one from high to low. */
		for (i = lhs->length - 1; i >= 0; --i)
		{
			if (lhs->blocks[i] == rhs->blocks[i])
			{
				continue;
			}
			else if (lhs->blocks[i] > rhs->blocks[i])
			{
				return 1;
			}
			else
			{
				return -1;
			}
		}

		/* no blocks differed */
		return 0;
	}

	/* result = lhs + rhs */
	static void BigInt_Add(BigInt* result, const BigInt* lhs, const BigInt* rhs)
	{
		/* determine which operand has the smaller length */
		const BigInt* large, * small;
		unsigned long long carry = 0;
		const unsigned int* largeCur, * smallCur, * largeEnd, * smallEnd;
		unsigned int* resultCur;

		if (lhs->length < rhs->length)
		{
			small = lhs;
			large = rhs;
		}
		else
		{
			small = rhs;
			large = lhs;
		}

		/* The output will be at least as long as the largest input */
		result->length = large->length;

		/* Add each block and add carry the overflow to the next block */
		largeCur = large->blocks;
		largeEnd = largeCur + large->length;
		smallCur = small->blocks;
		smallEnd = smallCur + small->length;
		resultCur = result->blocks;
		while (smallCur != smallEnd)
		{
			unsigned long long sum = carry + (unsigned long long)(*largeCur) +
				(unsigned long long)(*smallCur);
			carry = sum >> 32;
			*resultCur = sum & bitmask_u64(32);
			++largeCur;
			++smallCur;
			++resultCur;
		}

		/* Add the carry to any blocks that only exist in the large operand */
		while (largeCur != largeEnd)
		{
			unsigned long long sum = carry + (unsigned long long)(*largeCur);
			carry = sum >> 32;
			(*resultCur) = sum & bitmask_u64(32);
			++largeCur;
			++resultCur;
		}

		/* If there's still a carry, append a new block */
		if (carry != 0)
		{
			*resultCur = 1;
			result->length = large->length + 1;
		}
		else
		{
			result->length = large->length;
		}
	}

	/* result = lhs * rhs */
	static void BigInt_Multiply(BigInt* result, const BigInt* lhs, const BigInt* rhs)
	{
		const BigInt* large;
		const BigInt* small;
		unsigned int maxResultLen;
		unsigned int* cur, * end, * resultStart;
		const unsigned int* smallCur;

		/* determine which operand has the smaller length */
		if (lhs->length < rhs->length)
		{
			small = lhs;
			large = rhs;
		}
		else
		{
			small = rhs;
			large = lhs;
		}

		/* set the maximum possible result length */
		maxResultLen = large->length + small->length;

		/* clear the result data */
		for (cur = result->blocks, end = cur + maxResultLen; cur != end; ++cur)
		{
			*cur = 0;
		}

		/* perform standard long multiplication for each small block */
		resultStart = result->blocks;
		for (smallCur = small->blocks;
			smallCur != small->blocks + small->length;
			++smallCur, ++resultStart)
		{

			// * if non-zero, multiply against all the large blocks and add into the
			// * result
			// */
			const unsigned int multiplier = *smallCur;
			if (multiplier != 0)
			{
				const unsigned int* largeCur = large->blocks;
				unsigned int* resultCur = resultStart;
				unsigned long long carry = 0;
				do {
					unsigned long long product = (*resultCur) +
						(*largeCur) * (unsigned long long)multiplier + carry;
					carry = product >> 32;
					*resultCur = product & bitmask_u64(32);
					++largeCur;
					++resultCur;
				} while (largeCur != large->blocks + large->length);

				*resultCur = (unsigned int)(carry & bitmask_u64(32));
			}
		}

		/* check if the terminating block has no set bits */
		if (maxResultLen > 0 && result->blocks[maxResultLen - 1] == 0)
		{
			result->length = maxResultLen - 1;
		}
		else
		{
			result->length = maxResultLen;
		}
	}

	/* result = lhs * rhs */
	static void BigInt_Multiply_int(BigInt* result, const BigInt* lhs, unsigned int rhs)
	{
		/* perform long multiplication */
		unsigned int carry = 0;
		unsigned int* resultCur = result->blocks;
		const unsigned int* pLhsCur = lhs->blocks;
		const unsigned int* pLhsEnd = lhs->blocks + lhs->length;
		for (; pLhsCur != pLhsEnd; ++pLhsCur, ++resultCur)
		{
			unsigned long long product = (unsigned long long)(*pLhsCur) * rhs + carry;
			*resultCur = (unsigned int)(product & bitmask_u64(32));
			carry = product >> 32;
		}

		/* if there is a remaining carry, grow the array */
		if (carry != 0)
		{
			/* grow the array */
			*resultCur = (unsigned int)carry;
			result->length = lhs->length + 1;
		}
		else
		{
			result->length = lhs->length;
		}
	}

	/* result = in * 2 */
	static void BigInt_Multiply2(BigInt* result, const BigInt* in)
	{
		/* shift all the blocks by one */
		unsigned int carry = 0;

		unsigned int* resultCur = result->blocks;
		const unsigned int* pLhsCur = in->blocks;
		const unsigned int* pLhsEnd = in->blocks + in->length;
		for (; pLhsCur != pLhsEnd; ++pLhsCur, ++resultCur)
		{
			unsigned int cur = *pLhsCur;
			*resultCur = (cur << 1) | carry;
			carry = cur >> 31;
		}

		if (carry != 0)
		{
			/* grow the array */
			*resultCur = carry;
			result->length = in->length + 1;
		}
		else
		{
			result->length = in->length;
		}
	}

	/* result = result * 2 */
	static void BigInt_Multiply2_inplace(BigInt* result)
	{
		/* shift all the blocks by one */
		unsigned int carry = 0;

		unsigned int* cur = result->blocks;
		unsigned int* end = result->blocks + result->length;
		for (; cur != end; ++cur)
		{
			unsigned int tmpcur = *cur;
			*cur = (tmpcur << 1) | carry;
			carry = tmpcur >> 31;
		}

		if (carry != 0)
		{
			/* grow the array */
			*cur = carry;
			++result->length;
		}
	}

	/* result = result * 10 */
	static void BigInt_Multiply10(BigInt* result)
	{
		/* multiply all the blocks */
		unsigned long long carry = 0;

		unsigned int* cur = result->blocks;
		unsigned int* end = result->blocks + result->length;
		for (; cur != end; ++cur)
		{
			unsigned long long product = (unsigned long long)(*cur) * 10ull + carry;
			(*cur) = (unsigned int)(product & bitmask_u64(32));
			carry = product >> 32;
		}

		if (carry != 0)
		{
			/* grow the array */
			*cur = (unsigned int)carry;
			++result->length;
		}
	}

	static unsigned int g_PowerOf10_U32[] =
	{
		1,		  /* 10 ^ 0 */
		10,		 /* 10 ^ 1 */
		100,		/* 10 ^ 2 */
		1000,	   /* 10 ^ 3 */
		10000,	  /* 10 ^ 4 */
		100000,	 /* 10 ^ 5 */
		1000000,	/* 10 ^ 6 */
		10000000,   /* 10 ^ 7 */
	};


	// * Note: This has a lot of wasted space in the big integer structures of the
	// *	   early table entries. It wouldn't be terribly hard to make the multiply
	// *	   function work on integer pointers with an array length instead of
	// *	   the BigInt struct which would allow us to store a minimal amount of
	// *	   data here.
	// */
	static BigInt g_PowerOf10_Big[] =
	{
		/* 10 ^ 8 */
		{ 1, { 100000000 } },
		/* 10 ^ 16 */
		{ 2, { 0x6fc10000, 0x002386f2 } },
		/* 10 ^ 32 */
		{ 4, { 0x00000000, 0x85acef81, 0x2d6d415b, 0x000004ee, } },
		/* 10 ^ 64 */
		{ 7, { 0x00000000, 0x00000000, 0xbf6a1f01, 0x6e38ed64, 0xdaa797ed,
			   0xe93ff9f4, 0x00184f03, } },
		/* 10 ^ 128 */
		{ 14, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2e953e01,
				0x03df9909, 0x0f1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08,
				0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x0000024e, } },
		/* 10 ^ 256 */
		{ 27, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x982e7c01, 0xbed3875b,
				0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f,
				0x26b2716e, 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e,
				0xcc5573c0, 0x65f9ef17, 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc,
				0x5fdcefce, 0x000553f7, } },
		/* 10 ^ 512 */
		{ 54, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0xfc6cf801, 0x77f27267, 0x8f9546dc, 0x5d96976f,
				0xb83a8a97, 0xc31e1ad9, 0x46c40513, 0x94e65747, 0xc88976c1,
				0x4475b579, 0x28f8733b, 0xaa1da1bf, 0x703ed321, 0x1e25cfea,
				0xb21a2f22, 0xbc51fb2e, 0x96e14f5d, 0xbfa3edac, 0x329c57ae,
				0xe7fc7153, 0xc3fc0695, 0x85a91924, 0xf95f635e, 0xb2908ee0,
				0x93abade4, 0x1366732a, 0x9449775c, 0x69be5b0e, 0x7343afac,
				0xb099bc81, 0x45a71d46, 0xa2699748, 0x8cb07303, 0x8a0b1f13,
				0x8cab8a97, 0xc1d238d9, 0x633415d4, 0x0000001c, } },
		/* 10 ^ 1024 */
		{ 107, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x2919f001, 0xf55b2b72, 0x6e7c215b,
				0x1ec29f86, 0x991c4e87, 0x15c51a88, 0x140ac535, 0x4c7d1e1a,
				0xcc2cd819, 0x0ed1440e, 0x896634ee, 0x7de16cfb, 0x1e43f61f,
				0x9fce837d, 0x231d2b9c, 0x233e55c7, 0x65dc60d7, 0xf451218b,
				0x1c5cd134, 0xc9635986, 0x922bbb9f, 0xa7e89431, 0x9f9f2a07,
				0x62be695a, 0x8e1042c4, 0x045b7a74, 0x1abe1de3, 0x8ad822a5,
				0xba34c411, 0xd814b505, 0xbf3fdeb3, 0x8fc51a16, 0xb1b896bc,
				0xf56deeec, 0x31fb6bfd, 0xb6f4654b, 0x101a3616, 0x6b7595fb,
				0xdc1a47fe, 0x80d98089, 0x80bda5a5, 0x9a202882, 0x31eb0f66,
				0xfc8f1f90, 0x976a3310, 0xe26a7b7e, 0xdf68368a, 0x3ce3a0b8,
				0x8e4262ce, 0x75a351a2, 0x6cb0b6c9, 0x44597583, 0x31b5653f,
				0xc356e38a, 0x35faaba6, 0x0190fba0, 0x9fc4ed52, 0x88bc491b,
				0x1640114a, 0x005b8041, 0xf4f3235e, 0x1e8d4649, 0x36a8de06,
				0x73c55349, 0xa7e6bd2a, 0xc1a6970c, 0x47187094, 0xd2db49ef,
				0x926c3f5b, 0xae6209d4, 0x2d433949, 0x34f4a3c6, 0xd4305d94,
				0xd9d61a05, 0x00000325, } },
		/* 10 ^ 2048 */
		{ 213, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1333e001,
				0xe3096865, 0xb27d4d3f, 0x49e28dcf, 0xec2e4721, 0xee87e354,
				0xb6067584, 0x368b8abb, 0xa5e5a191, 0x2ed56d55, 0xfd827773,
				0xea50d142, 0x51b78db2, 0x98342c9e, 0xc850dabc, 0x866ed6f1,
				0x19342c12, 0x92794987, 0xd2f869c2, 0x66912e4a, 0x71c7fd8f,
				0x57a7842d, 0x235552eb, 0xfb7fedcc, 0xf3861ce0, 0x38209ce1,
				0x9713b449, 0x34c10134, 0x8c6c54de, 0xa7a8289c, 0x2dbb6643,
				0xe3cb64f3, 0x8074ff01, 0xe3892ee9, 0x10c17f94, 0xa8f16f92,
				0xa8281ed6, 0x967abbb3, 0x5a151440, 0x9952fbed, 0x13b41e44,
				0xafe609c3, 0xa2bca416, 0xf111821f, 0xfb1264b4, 0x91bac974,
				0xd6c7d6ab, 0x8e48ff35, 0x4419bd43, 0xc4a65665, 0x685e5510,
				0x33554c36, 0xab498697, 0x0dbd21fe, 0x3cfe491d, 0x982da466,
				0xcbea4ca7, 0x9e110c7b, 0x79c56b8a, 0x5fc5a047, 0x84d80e2e,
				0x1aa9f444, 0x730f203c, 0x6a57b1ab, 0xd752f7a6, 0x87a7dc62,
				0x944545ff, 0x40660460, 0x77c1a42f, 0xc9ac375d, 0xe866d7ef,
				0x744695f0, 0x81428c85, 0xa1fc6b96, 0xd7917c7b, 0x7bf03c19,
				0x5b33eb41, 0x5715f791, 0x8f6cae5f, 0xdb0708fd, 0xb125ac8e,
				0x785ce6b7, 0x56c6815b, 0x6f46eadb, 0x4eeebeee, 0x195355d8,
				0xa244de3c, 0x9d7389c0, 0x53761abd, 0xcf99d019, 0xde9ec24b,
				0x0d76ce39, 0x70beb181, 0x2e55ecee, 0xd5f86079, 0xf56d9d4b,
				0xfb8886fb, 0x13ef5a83, 0x408f43c5, 0x3f3389a4, 0xfad37943,
				0x58ccf45c, 0xf82df846, 0x415c7f3e, 0x2915e818, 0x8b3d5cf4,
				0x6a445f27, 0xf8dbb57a, 0xca8f0070, 0x8ad803ec, 0xb2e87c34,
				0x038f9245, 0xbedd8a6c, 0xc7c9dee0, 0x0eac7d56, 0x2ad3fa14,
				0xe0de0840, 0xf775677c, 0xf1bd0ad5, 0x92be221e, 0x87fa1fb9,
				0xce9d04a4, 0xd2c36fa9, 0x3f6f7024, 0xb028af62, 0x907855ee,
				0xd83e49d6, 0x4efac5dc, 0xe7151aab, 0x77cd8c6b, 0x0a753b7d,
				0x0af908b4, 0x8c983623, 0xe50f3027, 0x94222771, 0x1d08e2d6,
				0xf7e928e6, 0xf2ee5ca6, 0x1b61b93c, 0x11eb962b, 0x9648b21c,
				0xce2bcba1, 0x34f77154, 0x7bbebe30, 0xe526a319, 0x8ce329ac,
				0xde4a74d2, 0xb5dc53d5, 0x0009e8b3, } },
		/* 10 ^ 4096 */
		{ 426, { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
				0x00000000, 0x00000000, 0x00000000, 0x2a67c001, 0xd4724e8d,
				0x8efe7ae7, 0xf89a1e90, 0xef084117, 0x54e05154, 0x13b1bb51,
				0x506be829, 0xfb29b172, 0xe599574e, 0xf0da6146, 0x806c0ed3,
				0xb86ae5be, 0x45155e93, 0xc0591cc2, 0x7e1e7c34, 0x7c4823da,
				0x1d1f4cce, 0x9b8ba1e8, 0xd6bfdf75, 0xe341be10, 0xc2dfae78,
				0x016b67b2, 0x0f237f1a, 0x3dbeabcd, 0xaf6a2574, 0xcab3e6d7,
				0x142e0e80, 0x61959127, 0x2c234811, 0x87009701, 0xcb4bf982,
				0xf8169c84, 0x88052f8c, 0x68dde6d4, 0xbc131761, 0xff0b0905,
				0x54ab9c41, 0x7613b224, 0x1a1c304e, 0x3bfe167b, 0x441c2d47,
				0x4f6cea9c, 0x78f06181, 0xeb659fb8, 0x30c7ae41, 0x947e0d0e,
				0xa1ebcad7, 0xd97d9556, 0x2130504d, 0x1a8309cb, 0xf2acd507,
				0x3f8ec72a, 0xfd82373a, 0x95a842bc, 0x280f4d32, 0xf3618ac0,
				0x811a4f04, 0x6dc3a5b4, 0xd3967a1b, 0x15b8c898, 0xdcfe388f,
				0x454eb2a0, 0x8738b909, 0x10c4e996, 0x2bd9cc11, 0x3297cd0c,
				0x655fec30, 0xae0725b1, 0xf4090ee8, 0x037d19ee, 0x398c6fed,
				0x3b9af26b, 0xc994a450, 0xb5341743, 0x75a697b2, 0xac50b9c1,
				0x3ccb5b92, 0xffe06205, 0xa8329761, 0xdfea5242, 0xeb83cadb,
				0xe79dadf7, 0x3c20ee69, 0x1e0a6817, 0x7021b97a, 0x743074fa,
				0x176ca776, 0x77fb8af6, 0xeca19beb, 0x92baf1de, 0xaf63b712,
				0xde35c88b, 0xa4eb8f8c, 0xe137d5e9, 0x40b464a0, 0x87d1cde8,
				0x42923bbd, 0xcd8f62ff, 0x2e2690f3, 0x095edc16, 0x59c89f1b,
				0x1fa8fd5d, 0x5138753d, 0x390a2b29, 0x80152f18, 0x2dd8d925,
				0xf984d83e, 0x7a872e74, 0xc19e1faf, 0xed4d542d, 0xecf9b5d0,
				0x9462ea75, 0xc53c0adf, 0x0caea134, 0x37a2d439, 0xc8fa2e8a,
				0x2181327e, 0x6e7bb827, 0x2d240820, 0x50be10e0, 0x5893d4b8,
				0xab312bb9, 0x1f2b2322, 0x440b3f25, 0xbf627ede, 0x72dac789,
				0xb608b895, 0x78787e2a, 0x86deb3f0, 0x6fee7aab, 0xbb9373f4,
				0x27ecf57b, 0xf7d8b57e, 0xfca26a9f, 0x3d04e8d2, 0xc9df13cb,
				0x3172826a, 0xcd9e8d7c, 0xa8fcd8e0, 0xb2c39497, 0x307641d9,
				0x1cc939c1, 0x2608c4cf, 0xb6d1c7bf, 0x3d326a7e, 0xeeaf19e6,
				0x8e13e25f, 0xee63302b, 0x2dfe6d97, 0x25971d58, 0xe41d3cc4,
				0x0a80627c, 0xab8db59a, 0x9eea37c8, 0xe90afb77, 0x90ca19cf,
				0x9ee3352c, 0x3613c850, 0xfe78d682, 0x788f6e50, 0x5b060904,
				0xb71bd1a4, 0x3fecb534, 0xb32c450c, 0x20c33857, 0xa6e9cfda,
				0x0239f4ce, 0x48497187, 0xa19adb95, 0xb492ed8a, 0x95aca6a8,
				0x4dcd6cd9, 0xcf1b2350, 0xfbe8b12a, 0x1a67778c, 0x38eb3acc,
				0xc32da383, 0xfb126ab1, 0xa03f40a8, 0xed5bf546, 0xe9ce4724,
				0x4c4a74fd, 0x73a130d8, 0xd9960e2d, 0xa2ebd6c1, 0x94ab6feb,
				0x6f233b7c, 0x49126080, 0x8e7b9a73, 0x4b8c9091, 0xd298f999,
				0x35e836b5, 0xa96ddeff, 0x96119b31, 0x6b0dd9bc, 0xc6cc3f8d,
				0x282566fb, 0x72b882e7, 0xd6769f3b, 0xa674343d, 0x00fc509b,
				0xdcbf7789, 0xd6266a3f, 0xae9641fd, 0x4e89541b, 0x11953407,
				0x53400d03, 0x8e0dd75a, 0xe5b53345, 0x108f19ad, 0x108b89bc,
				0x41a4c954, 0xe03b2b63, 0x437b3d7f, 0x97aced8e, 0xcbd66670,
				0x2c5508c2, 0x650ebc69, 0x5c4f2ef0, 0x904ff6bf, 0x9985a2df,
				0x9faddd9e, 0x5ed8d239, 0x25585832, 0xe3e51cb9, 0x0ff4f1d4,
				0x56c02d9a, 0x8c4ef804, 0xc1a08a13, 0x13fd01c8, 0xe6d27671,
				0xa7c234f4, 0x9d0176cc, 0xd0d73df2, 0x4d8bfa89, 0x544f10cd,
				0x2b17e0b2, 0xb70a5c7d, 0xfd86fe49, 0xdf373f41, 0x214495bb,
				0x84e857fd, 0x00d313d5, 0x0496fcbe, 0xa4ba4744, 0xe8cac982,
				0xaec29e6e, 0x87ec7038, 0x7000a519, 0xaeee333b, 0xff66e42c,
				0x8afd6b25, 0x03b4f63b, 0xbd7991dc, 0x5ab8d9c7, 0x2ed4684e,
				0x48741a6c, 0xaf06940d, 0x2fdc6349, 0xb03d7ecd, 0xe974996f,
				0xac7867f9, 0x52ec8721, 0xbcdd9d4a, 0x8edd2d00, 0x3557de06,
				0x41c759f8, 0x3956d4b9, 0xa75409f2, 0x123cd8a1, 0xb6100fab,
				0x3e7b21e2, 0x2e8d623b, 0x92959da2, 0xbca35f77, 0x200c03a5,
				0x35fcb457, 0x1bb6c6e4, 0xf74eb928, 0x3d5d0b54, 0x87cc1d21,
				0x4964046f, 0x18ae4240, 0xd868b275, 0x8bd2b496, 0x1c5563f4,
				0xc234d8f5, 0xf868e970, 0xf9151fff, 0xae7be4a2, 0x271133ee,
				0xbb0fd922, 0x25254932, 0xa60a9fc0, 0x104bcd64, 0x30290145,
				0x00000062, } }
	};

	/* result = 10^exponent */
	static void BigInt_Pow10(BigInt* result, unsigned int exponent, BigInt* temp)
	{
		/* use two temporary values to reduce large integer copy operations */
		BigInt* curTemp = result;
		BigInt* pNextTemp = temp;
		unsigned int smallExponent;
		unsigned int tableIdx = 0;


		// * initialize the result by looking up a 32-bit power of 10 corresponding to
		// * the first 3 bits
		// */
		smallExponent = exponent & bitmask_u32(3);
		BigInt_Set_uint32(curTemp, g_PowerOf10_U32[smallExponent]);

		/* remove the low bits that we used for the 32-bit lookup table */
		exponent >>= 3;

		/* while there are remaining bits in the exponent to be processed */
		while (exponent != 0)
		{
			/* if the current bit is set, multiply by this power of 10 */
			if (exponent & 1)
			{
				BigInt* pSwap;

				/* multiply into the next temporary */
				BigInt_Multiply(pNextTemp, curTemp, &g_PowerOf10_Big[tableIdx]);

				/* swap to the next temporary */
				pSwap = curTemp;
				curTemp = pNextTemp;
				pNextTemp = pSwap;
			}

			/* advance to the next bit */
			++tableIdx;
			exponent >>= 1;
		}

		/* output the result */
		if (curTemp != result)
		{
			BigInt_Copy(result, curTemp);
		}
	}

	/* in = in * 10^exponent */
	static void BigInt_MultiplyPow10(BigInt* in, unsigned int exponent, BigInt* temp)
	{
		/* use two temporary values to reduce large integer copy operations */
		BigInt* curTemp, * pNextTemp;
		unsigned int smallExponent;
		unsigned int tableIdx = 0;


		// * initialize the result by looking up a 32-bit power of 10 corresponding to
		// * the first 3 bits
		// */
		smallExponent = exponent & bitmask_u32(3);
		if (smallExponent != 0)
		{
			BigInt_Multiply_int(temp, in, g_PowerOf10_U32[smallExponent]);
			curTemp = temp;
			pNextTemp = in;
		}
		else
		{
			curTemp = in;
			pNextTemp = temp;
		}

		/* remove the low bits that we used for the 32-bit lookup table */
		exponent >>= 3;

		/* while there are remaining bits in the exponent to be processed */
		while (exponent != 0)
		{
			/* if the current bit is set, multiply by this power of 10 */
			if (exponent & 1)
			{
				BigInt* pSwap;

				/* multiply into the next temporary */
				BigInt_Multiply(pNextTemp, curTemp, &g_PowerOf10_Big[tableIdx]);

				/* swap to the next temporary */
				pSwap = curTemp;
				curTemp = pNextTemp;
				pNextTemp = pSwap;
			}

			/* advance to the next bit */
			++tableIdx;
			exponent >>= 1;
		}

		/* output the result */
		if (curTemp != in) {
			BigInt_Copy(in, curTemp);
		}
	}

	/* result = 2^exponent */
	static inline void BigInt_Pow2(BigInt* result, const unsigned int exponent)
	{
		unsigned int bitIdx;
		unsigned int blockIdx = exponent >> 5;
		unsigned int i;

		for (i = 0; i <= blockIdx; ++i)
		{
			result->blocks[i] = 0;
		}

		result->length = blockIdx + 1;

		bitIdx = exponent - (blockIdx << 5);
		result->blocks[blockIdx] |= ((unsigned int)1 << bitIdx);
	}


	// * This function will divide two large numbers under the assumption that the
	// * result is within the range [0,10) and the input numbers have been shifted
	// * to satisfy:
	// * - The highest block of the divisor is greater than or equal to 8 such that
	// *   there is enough precision to make an accurate first guess at the quotient.
	// * - The highest block of the divisor is less than the maximum value on an
	// *   unsigned 32-bit integer such that we can safely increment without overflow.
	// * - The dividend does not contain more blocks than the divisor such that we
	// *   can estimate the quotient by dividing the equivalently placed high blocks.
	// *
	// * quotient  = floor(dividend / divisor)
	// * remainder = dividend - quotient*divisor
	// *
	// * dividend is updated to be the remainder and the quotient is returned.
	// */
	static unsigned int BigInt_DivideWithRemainder_MaxQuotient9(BigInt* dividend, const BigInt* divisor)
	{
		unsigned int length, quotient;
		const unsigned int* finalDivisorBlock;
		unsigned int* finalDividendBlock;


		// * If the dividend is smaller than the divisor, the quotient is zero and the
		// * divisor is already the remainder.
		// */
		length = divisor->length;
		if (dividend->length < divisor->length)
		{
			return 0;
		}

		finalDivisorBlock = divisor->blocks + length - 1;
		finalDividendBlock = dividend->blocks + length - 1;


		// * Compute an estimated quotient based on the high block value. This will
		// * either match the actual quotient or undershoot by one.
		// */
		quotient = *finalDividendBlock / (*finalDivisorBlock + 1);

		/* Divide out the estimated quotient */
		if (quotient != 0)
		{
			/* dividend = dividend - divisor*quotient */
			const unsigned int* divisorCur = divisor->blocks;
			unsigned int* dividendCur = dividend->blocks;

			unsigned long long borrow = 0;
			unsigned long long carry = 0;
			do {
				unsigned long long difference, product;

				product = (unsigned long long) * divisorCur * (unsigned long long)quotient + carry;
				carry = product >> 32;

				difference = (unsigned long long) * dividendCur
					- (product & bitmask_u64(32)) - borrow;
				borrow = (difference >> 32) & 1;

				*dividendCur = difference & bitmask_u64(32);

				++divisorCur;
				++dividendCur;
			} while (divisorCur <= finalDivisorBlock);

			/* remove all leading zero blocks from dividend */
			while (length > 0 && dividend->blocks[length - 1] == 0)
			{
				--length;
			}

			dividend->length = length;
		}


		// * If the dividend is still larger than the divisor, we overshot our
		// * estimate quotient. To correct, we increment the quotient and subtract one
		// * more divisor from the dividend.
		// */
		if (BigInt_Compare(dividend, divisor) >= 0)
		{
			/* dividend = dividend - divisor */
			const unsigned int* divisorCur = divisor->blocks;
			unsigned int* dividendCur = dividend->blocks;
			unsigned long long borrow = 0;

			++quotient;

			do {
				unsigned long long difference = (unsigned long long) * dividendCur
					- (unsigned long long) * divisorCur - borrow;
				borrow = (difference >> 32) & 1;

				*dividendCur = difference & bitmask_u64(32);

				++divisorCur;
				++dividendCur;
			} while (divisorCur <= finalDivisorBlock);

			/* remove all leading zero blocks from dividend */
			while (length > 0 && dividend->blocks[length - 1] == 0)
			{
				--length;
			}

			dividend->length = length;
		}

		return quotient;
	}

	/* result = result << shift */
	static void BigInt_ShiftLeft(BigInt* result, unsigned int shift)
	{
		unsigned int shiftBlocks = shift >> 5;
		unsigned int shiftBits = shift - (shiftBlocks << 5);

		/* process blocks high to low so that we can safely process in place */
		const unsigned int* pInBlocks = result->blocks;
		int inLength = result->length;
		unsigned int* pInCur, * pOutCur;

		/* check if the shift is block aligned */
		if (shiftBits == 0)
		{
			unsigned int i;

			/* copy blocks from high to low */
			for (pInCur = result->blocks + result->length,
				pOutCur = pInCur + shiftBlocks;
				pInCur >= pInBlocks;
				--pInCur, --pOutCur)
			{
				*pOutCur = *pInCur;
			}

			/* zero the remaining low blocks */
			for (i = 0; i < shiftBlocks; ++i)
			{
				result->blocks[i] = 0;
			}

			result->length += shiftBlocks;
		}
		/* else we need to shift partial blocks */
		else
		{
			unsigned int i;
			int inBlockIdx = inLength - 1;
			unsigned int outBlockIdx = inLength + shiftBlocks;

			/* output the initial blocks */
			const unsigned int lowBitsShift = (32 - shiftBits);
			unsigned int highBits = 0;
			unsigned int block = result->blocks[inBlockIdx];
			unsigned int lowBits = block >> lowBitsShift;

			/* set the length to hold the shifted blocks */
			result->length = outBlockIdx + 1;

			while (inBlockIdx > 0)
			{
				result->blocks[outBlockIdx] = highBits | lowBits;
				highBits = block << shiftBits;

				--inBlockIdx;
				--outBlockIdx;

				block = result->blocks[inBlockIdx];
				lowBits = block >> lowBitsShift;
			}

			/* output the final blocks */
			result->blocks[outBlockIdx] = highBits | lowBits;
			result->blocks[outBlockIdx - 1] = block << shiftBits;

			/* zero the remaining low blocks */
			for (i = 0; i < shiftBlocks; ++i)
			{
				result->blocks[i] = 0;
			}

			/* check if the terminating block has no set bits */
			if (result->blocks[result->length - 1] == 0)
			{
				--result->length;
			}
		}
	}



	// * This is an implementation the Dragon4 algorithm to convert a binary number in
	// * floating point format to a decimal number in string format. The function
	// * returns the number of digits written to the output buffer and the output is
	// * not NUL terminated.
	// *
	// * The floating point input value is (mantissa// * 2^exponent).
	// *
	// * See the following papers for more information on the algorithm:
	// *  "How to Print Floating-Point Numbers Accurately"
	// *	Steele and White
	// *	http://kurtstephens.com/files/p372-steele.pdf
	// *  "Printing Floating-Point Numbers Quickly and Accurately"
	// *	Burger and Dybvig
	// *	http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656
	// *
	// * This implementation is essentially a port of the "Figure 3" Scheme code from
	// * Burger and Dybvig, but with the following additional differences:
	// *   1. Instead of finding the highest k such that high < B**k, we search
	// *	  for the one where v < B**k. This has a downside that if a power
	// *	  of 10 exists between v and high, we will output a 9 instead of a 1 as
	// *	  first digit, violating the "no-carry" guarantee of the paper. This is
	// *	  accounted for in a new post-processing loop which implements a carry
	// *	  operation. The upside is one less BigInt multiplication.
	// *   2. The approximate value of k found is offset by a different amount
	// *	  (0.69), in order to hit the "fast" branch more often. This is
	// *	  extensively described on Ryan Juckett's website.
	// *   3. The fixed precision mode is much simpler than proposed in the paper.
	// *	  It simply outputs digits by repeatedly dividing by 10. The new "carry"
	// *	  loop at the end rounds this output nicely.
	// *  There is also some new code to account for details of the BigInt
	// *  implementation, which are not present in the paper since it does not specify
	// *  details of the integer calculations.
	// *
	// * There is some more documentation of these changes on Ryan Juckett's website
	// * at http://www.ryanjuckett.com/programming/printing-floating-point-numbers/
	// *
	// * This code also has a few implementation differences from Ryan Juckett's
	// * version:
	// *  1. fixed overflow problems when mantissa was 64 bits (in float128 types),
	// *	 by replacing multiplication by 2 or 4 by BigInt_ShiftLeft calls.
	// *  2. Increased c_BigInt_MaxBlocks, for 128-bit floats
	// *  3. Added more entries to the g_PowerOf10_Big table, for 128-bit floats.
	// *  4. Added unbiased rounding calculation with isEven. Ryan Juckett's
	// *	 implementation did not implement "IEEE unbiased rounding", except in the
	// *	 last digit. This has been added back, following the Burger & Dybvig
	// *	 code, using the isEven variable.
	// *
	// * Arguments:
	// *  * bigints - memory to store all bigints needed (7) for dragon4 computation.
	// *			   The first BigInt should be filled in with the mantissa.
	// *  * exponent - value exponent in base 2
	// *  * mantissaBit - index of the highest set mantissa bit
	// *  * hasUnequalMargins - is the high margin twice as large as the low margin
	// *  * cutoffMode - how to interpret cutoff_*: fractional or total digits?
	// *  * cutoff_max - cut off printing after this many digits. -1 for no cutoff
	// *  * cutoff_min - print at least this many digits. -1 for no cutoff
	// *  * pOutBuffer - buffer to output into
	// *  * bufferSize - maximum characters that can be printed to pOutBuffer
	// *  * pOutExponent - the base 10 exponent of the first digit
	// *
	// * Returns the number of digits written to the output buffer.
	// */
	static unsigned int Dragon4(BigInt* bigints, const int exponent,
		const unsigned int mantissaBit, const int hasUnequalMargins,
		const DigitMode digitMode, const CutoffMode cutoffMode,
		int cutoff_max, int cutoff_min, char* pOutBuffer,
		unsigned int bufferSize, int* pOutExponent)
	{
		char* curDigit = pOutBuffer;


		// * We compute values in integer format by rescaling as
		// *   mantissa = scaledValue / scale
		// *   marginLow = scaledMarginLow / scale
		// *   marginHigh = scaledMarginHigh / scale
		// * Here, marginLow and marginHigh represent 1/2 of the distance to the next
		// * floating point value above/below the mantissa.
		// *
		// * scaledMarginHigh will point to scaledMarginLow in the case they must be
		// * equal to each other, otherwise it will point to optionalMarginHigh.
		// */
		BigInt* mantissa = &bigints[0];  /* the only initialized bigint */
		BigInt* scale = &bigints[1];
		BigInt* scaledValue = &bigints[2];
		BigInt* scaledMarginLow = &bigints[3];
		BigInt* scaledMarginHigh;
		BigInt* optionalMarginHigh = &bigints[4];

		BigInt* temp1 = &bigints[5];
		BigInt* temp2 = &bigints[6];

		const double log10_2 = 0.30102999566398119521373889472449;
		int digitExponent, hiBlock;
		int cutoff_max_Exponent, cutoff_min_Exponent;
		unsigned int outputDigit;	/* current digit being output */
		unsigned int outputLen;
		int isEven = BigInt_IsEven(mantissa);
		int cmp;

		/* values used to determine how to round */
		int low, high, roundDown;

		/* if the mantissa is zero, the value is zero regardless of the exponent */
		if (BigInt_IsZero(mantissa))
		{
			*curDigit = '0';
			*pOutExponent = 0;
			return 1;
		}

		BigInt_Copy(scaledValue, mantissa);

		if (hasUnequalMargins)
		{
			/* if we have no fractional component */
			if (exponent > 0)
			{

				// * 1) Expand the input value by multiplying out the mantissa and
				// *	exponent. This represents the input value in its whole number
				// *	representation.
				// * 2) Apply an additional scale of 2 such that later comparisons
				// *	against the margin values are simplified.
				// * 3) Set the margin value to the lowest mantissa bit's scale.
				// */

				/* scaledValue	  = 2 * 2 * mantissa*2^exponent */
				BigInt_ShiftLeft(scaledValue, exponent + 2);
				/* scale			= 2 * 2 * 1 */
				BigInt_Set_uint32(scale, 4);
				/* scaledMarginLow  = 2 * 2^(exponent-1) */
				BigInt_Pow2(scaledMarginLow, exponent);
				/* scaledMarginHigh = 2 * 2 * 2^(exponent-1) */
				BigInt_Pow2(optionalMarginHigh, exponent + 1);
			}
			/* else we have a fractional exponent */
			else
			{

				// * In order to track the mantissa data as an integer, we store it as
				// * is with a large scale
				// */

				/* scaledValue	  = 2 * 2 * mantissa */
				BigInt_ShiftLeft(scaledValue, 2);
				/* scale			= 2 * 2 * 2^(-exponent) */
				BigInt_Pow2(scale, -exponent + 2);
				/* scaledMarginLow  = 2 * 2^(-1) */
				BigInt_Set_uint32(scaledMarginLow, 1);
				/* scaledMarginHigh = 2 * 2 * 2^(-1) */
				BigInt_Set_uint32(optionalMarginHigh, 2);
			}

			/* the high and low margins are different */
			scaledMarginHigh = optionalMarginHigh;
		}
		else
		{
			/* if we have no fractional component */
			if (exponent > 0)
			{
				/* scaledValue	 = 2 * mantissa*2^exponent */
				BigInt_ShiftLeft(scaledValue, exponent + 1);
				/* scale		   = 2 * 1 */
				BigInt_Set_uint32(scale, 2);
				/* scaledMarginLow = 2 * 2^(exponent-1) */
				BigInt_Pow2(scaledMarginLow, exponent);
			}
			/* else we have a fractional exponent */
			else
			{

				// * In order to track the mantissa data as an integer, we store it as
				// * is with a large scale
				// */

				/* scaledValue	 = 2 * mantissa */
				BigInt_ShiftLeft(scaledValue, 1);
				/* scale		   = 2 * 2^(-exponent) */
				BigInt_Pow2(scale, -exponent + 1);
				/* scaledMarginLow = 2 * 2^(-1) */
				BigInt_Set_uint32(scaledMarginLow, 1);
			}

			/* the high and low margins are equal */
			scaledMarginHigh = scaledMarginLow;
		}


		// * Compute an estimate for digitExponent that will be correct or undershoot
		// * by one.  This optimization is based on the paper "Printing Floating-Point
		// * Numbers Quickly and Accurately" by Burger and Dybvig
		// * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.72.4656
		// * We perform an additional subtraction of 0.69 to increase the frequency of
		// * a failed estimate because that lets us take a faster branch in the code.
		// * 0.69 is chosen because 0.69 + log10(2) is less than one by a reasonable
		// * epsilon that will account for any floating point error.
		// *
		// * We want to set digitExponent to floor(log10(v)) + 1
		// *  v = mantissa*2^exponent
		// *  log2(v) = log2(mantissa) + exponent;
		// *  log10(v) = log2(v) * log10(2)
		// *  floor(log2(v)) = mantissaBit + exponent;
		// *  log10(v) - log10(2) < (mantissaBit + exponent) * log10(2) <= log10(v)
		// *  log10(v) < (mantissaBit + exponent) * log10(2) + log10(2)
		// *												 <= log10(v) + log10(2)
		// *  floor(log10(v)) < ceil((mantissaBit + exponent) * log10(2))
		// *												 <= floor(log10(v)) + 1
		// *
		// *  Warning: This calculation assumes double is an IEEE-binary64
		// *  float. This line may need to be updated if this is not the case.
		// */
		digitExponent = (int)CEIL(((int)mantissaBit + exponent) * log10_2 - 0.69);


		// * if the digit exponent is smaller than the smallest desired digit for
		// * fractional cutoff, pull the digit back into legal range at which point we
		// * will round to the appropriate value.  Note that while our value for
		// * digitExponent is still an estimate, this is safe because it only
		// * increases the number. This will either correct digitExponent to an
		// * accurate value or it will clamp it above the accurate value.
		// */
		if (cutoff_max >= 0 && cutoffMode == CutoffMode_FractionLength &&
			digitExponent <= -cutoff_max)
		{
			digitExponent = -cutoff_max + 1;
		}


		/* Divide value by 10^digitExponent. */
		if (digitExponent > 0)
		{
			/* A positive exponent creates a division so we multiply the scale. */
			BigInt_MultiplyPow10(scale, digitExponent, temp1);
		}
		else if (digitExponent < 0)
		{

			// * A negative exponent creates a multiplication so we multiply up the
			// * scaledValue, scaledMarginLow and scaledMarginHigh.
			// */
			BigInt* temp = temp1, * pow10 = temp2;
			BigInt_Pow10(pow10, -digitExponent, temp);

			BigInt_Multiply(temp, scaledValue, pow10);
			BigInt_Copy(scaledValue, temp);

			BigInt_Multiply(temp, scaledMarginLow, pow10);
			BigInt_Copy(scaledMarginLow, temp);

			if (scaledMarginHigh != scaledMarginLow)
			{
				BigInt_Multiply2(scaledMarginHigh, scaledMarginLow);
			}
		}

		/* If (value >= 1), our estimate for digitExponent was too low */
		if (BigInt_Compare(scaledValue, scale) >= 0)
		{

			// * The exponent estimate was incorrect.
			// * Increment the exponent and don't perform the premultiply needed
			// * for the first loop iteration.
			// */
			digitExponent = digitExponent + 1;
		}
		else
		{

			// * The exponent estimate was correct.
			// * Multiply larger by the output base to prepare for the first loop
			// * iteration.
			// */
			BigInt_Multiply10(scaledValue);
			BigInt_Multiply10(scaledMarginLow);
			if (scaledMarginHigh != scaledMarginLow)
			{
				BigInt_Multiply2(scaledMarginHigh, scaledMarginLow);
			}
		}


		// * Compute the cutoff_max exponent (the exponent of the final digit to
		// * print).  Default to the maximum size of the output buffer.
		// */
		cutoff_max_Exponent = digitExponent - bufferSize;
		if (cutoff_max >= 0)
		{
			int desiredCutoffExponent;

			if (cutoffMode == CutoffMode_TotalLength)
			{
				desiredCutoffExponent = digitExponent - cutoff_max;
				if (desiredCutoffExponent > cutoff_max_Exponent)
				{
					cutoff_max_Exponent = desiredCutoffExponent;
				}
			}
			/* Otherwise it's CutoffMode_FractionLength. Print cutoff_max digits
			// * past the decimal point or until we reach the buffer size
			// */
			else
			{
				desiredCutoffExponent = -cutoff_max;
				if (desiredCutoffExponent > cutoff_max_Exponent)
				{
					cutoff_max_Exponent = desiredCutoffExponent;
				}
			}
		}
		/* Also compute the cutoff_min exponent. */
		cutoff_min_Exponent = digitExponent;
		if (cutoff_min >= 0)
		{
			int desiredCutoffExponent;

			if (cutoffMode == CutoffMode_TotalLength)
			{
				desiredCutoffExponent = digitExponent - cutoff_min;
				if (desiredCutoffExponent < cutoff_min_Exponent)
				{
					cutoff_min_Exponent = desiredCutoffExponent;
				}
			}
			else
			{
				desiredCutoffExponent = -cutoff_min;
				if (desiredCutoffExponent < cutoff_min_Exponent)
				{
					cutoff_min_Exponent = desiredCutoffExponent;
				}
			}
		}

		/* Output the exponent of the first digit we will print */
		*pOutExponent = digitExponent - 1;


		// * In preparation for calling BigInt_DivideWithRemainder_MaxQuotient9(), we
		// * need to scale up our values such that the highest block of the
		// * denominator is greater than or equal to 8. We also need to guarantee that
		// * the numerator can never have a length greater than the denominator after
		// * each loop iteration.  This requires the highest block of the denominator
		// * to be less than or equal to 429496729 which is the highest number that
		// * can be multiplied by 10 without overflowing to a new block.
		// */
		hiBlock = scale->blocks[scale->length - 1];
		if (hiBlock < 8 || hiBlock > 429496729)
		{
			unsigned int hiBlockLog2, shift;


			// * Perform a bit shift on all values to get the highest block of the
			// * denominator into the range [8,429496729]. We are more likely to make
			// * accurate quotient estimations in
			// * BigInt_DivideWithRemainder_MaxQuotient9() with higher denominator
			// * values so we shift the denominator to place the highest bit at index
			// * 27 of the highest block.  This is safe because (2^28 - 1) = 268435455
			// * which is less than 429496729. This means that all values with a
			// * highest bit at index 27 are within range.
			// */
			hiBlockLog2 = LogBase2_32(hiBlock);
			shift = (32 + 27 - hiBlockLog2);
			shift = shift - (shift >> 5 << 5);

			BigInt_ShiftLeft(scale, shift);
			BigInt_ShiftLeft(scaledValue, shift);
			BigInt_ShiftLeft(scaledMarginLow, shift);
			if (scaledMarginHigh != scaledMarginLow)
			{
				BigInt_Multiply2(scaledMarginHigh, scaledMarginLow);
			}
		}

		if (digitMode == DigitMode_Unique)
		{

			// * For the unique cutoff mode, we will try to print until we have
			// * reached a level of precision that uniquely distinguishes this value
			// * from its neighbors. If we run out of space in the output buffer, we
			// * terminate early.
			// */
			for (;;)
			{
				BigInt* scaledValueHigh = temp1;

				digitExponent = digitExponent - 1;

				/* divide out the scale to extract the digit */
				outputDigit =
					BigInt_DivideWithRemainder_MaxQuotient9(scaledValue, scale);

				/* update the high end of the value */
				BigInt_Add(scaledValueHigh, scaledValue, scaledMarginHigh);


				// * stop looping if we are far enough away from our neighboring
				// * values (and we have printed at least the requested minimum
				// * digits) or if we have reached the cutoff digit
				// */
				cmp = BigInt_Compare(scaledValue, scaledMarginLow);
				low = isEven ? (cmp <= 0) : (cmp < 0);
				cmp = BigInt_Compare(scaledValueHigh, scale);
				high = isEven ? (cmp >= 0) : (cmp > 0);
				if (((low | high) & (digitExponent <= cutoff_min_Exponent)) | (digitExponent == cutoff_max_Exponent))
				{
					break;
				}

				/* store the output digit */
				*curDigit = (char)('0' + outputDigit);
				++curDigit;

				/* multiply larger by the output base */
				BigInt_Multiply10(scaledValue);
				BigInt_Multiply10(scaledMarginLow);
				if (scaledMarginHigh != scaledMarginLow)
				{
					BigInt_Multiply2(scaledMarginHigh, scaledMarginLow);
				}
			}
		}
		else
		{

			// * For exact digit mode, we will try to print until we
			// * have exhausted all precision (i.e. all remaining digits are zeros) or
			// * until we reach the desired cutoff digit.
			// */
			low = false;
			high = false;

			for (;;)
			{
				digitExponent = digitExponent - 1;

				/* divide out the scale to extract the digit */
				outputDigit =
					BigInt_DivideWithRemainder_MaxQuotient9(scaledValue, scale);

				if ((scaledValue->length == 0) | (digitExponent == cutoff_max_Exponent))
				{
					break;
				}

				/* store the output digit */
				*curDigit = (char)('0' + outputDigit);
				++curDigit;

				/* multiply larger by the output base */
				BigInt_Multiply10(scaledValue);
			}
		}

		/* default to rounding down the final digit if value got too close to 0 */
		roundDown = low;

		/* if it is legal to round up and down */
		if (low == high)
		{
			int compare;


			// * round to the closest digit by comparing value with 0.5. To do this we
			// * need to convert the inequality to large integer values.
			// *  compare( value, 0.5 )
			// *  compare( scale * value, scale * 0.5 )
			// *  compare( 2 * scale * value, scale )
			// */
			BigInt_Multiply2_inplace(scaledValue);
			compare = BigInt_Compare(scaledValue, scale);
			roundDown = compare < 0;


			// * if we are directly in the middle, round towards the even digit (i.e.
			// * IEEE rounding rules)
			// */
			if (compare == 0)
			{
				roundDown = (outputDigit & 1) == 0;
			}
		}

		/* print the rounded digit */
		if (roundDown)
		{
			*curDigit = (char)('0' + outputDigit);
			++curDigit;
		}
		else
		{
			/* handle rounding up */
			if (outputDigit == 9)
			{
				/* find the first non-nine prior digit */
				for (;;)
				{
					/* if we are at the first digit */
					if (curDigit == pOutBuffer)
					{
						/* output 1 at the next highest exponent */
						*curDigit = '1';
						++curDigit;
						*pOutExponent += 1;
						break;
					}

					--curDigit;
					if (*curDigit != '9')
					{
						/* increment the digit */
						*curDigit += 1;
						++curDigit;
						break;
					}
				}
			}
			else
			{
				/* values in the range [0,8] can perform a simple round up */
				*curDigit = (char)('0' + outputDigit + 1);
				++curDigit;
			}
		}

		/* return the number of digits output */
		outputLen = (unsigned int)(curDigit - pOutBuffer);

		return outputLen;
	}


	// * Outputs the positive number with positional notation: ddddd.dddd
	// * The output is always NUL terminated and the output length (not including the
	// * NUL) is returned.
	// *
	// * Arguments:
	// *	buffer - buffer to output into
	// *	bufferSize - maximum characters that can be printed to buffer
	// *	mantissa - value significand
	// *	exponent - value exponent in base 2
	// *	signbit - value of the sign position. Should be '+', '-' or ''
	// *	mantissaBit - index of the highest set mantissa bit
	// *	hasUnequalMargins - is the high margin twice as large as the low margin
	// *
	// * See Options for description of remaining arguments.
	// */
	static unsigned int FormatPositional(char* buffer, unsigned int bufferSize, BigInt* mantissa,
		int exponent, char signbit, unsigned int mantissaBit,
		int hasUnequalMargins, DigitMode digit_mode,
		CutoffMode cutoff_mode, int precision,
		int min_digits, TrimMode trim_mode,
		int digits_left, int digits_right)
	{
		int printExponent;
		int numDigits, numWholeDigits = 0, has_sign = 0;
		int add_digits;

		int maxPrintLen = (int)bufferSize - 1, pos = 0;

		/* track the # of digits past the decimal point that have been printed */
		int numFractionDigits = 0, desiredFractionalDigits;

		if (signbit == '+' && pos < maxPrintLen)
		{
			buffer[pos++] = '+';
			has_sign = 1;
		}
		else if (signbit == '-' && pos < maxPrintLen)
		{
			buffer[pos++] = '-';
			has_sign = 1;
		}

		numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins,
			digit_mode, cutoff_mode, precision, min_digits,
			buffer + has_sign, maxPrintLen - has_sign,
			&printExponent);

		/* if output has a whole number */
		if (printExponent >= 0)
		{
			/* leave the whole number at the start of the buffer */
			numWholeDigits = printExponent + 1;
			if (numDigits <= numWholeDigits)
			{
				int count = numWholeDigits - numDigits;
				pos += numDigits;

				/* don't overflow the buffer */
				if (pos + count > maxPrintLen)
				{
					count = maxPrintLen - pos;
				}

				/* add trailing zeros up to the decimal point */
				numDigits += count;
				for (; count > 0; count--)
				{
					buffer[pos++] = '0';
				}
			}
			/* insert the decimal point prior to the fraction */
			else if (numDigits > numWholeDigits)
			{
				int maxFractionDigits;

				numFractionDigits = numDigits - numWholeDigits;
				maxFractionDigits = maxPrintLen - numWholeDigits - 1 - pos;
				if (numFractionDigits > maxFractionDigits)
				{
					numFractionDigits = maxFractionDigits;
				}

				movemem(buffer + pos + numWholeDigits + 1,
					buffer + pos + numWholeDigits, numFractionDigits);
				pos += numWholeDigits;
				buffer[pos] = '.';
				numDigits = numWholeDigits + 1 + numFractionDigits;
				pos += 1 + numFractionDigits;
			}
		}
		else
		{
			/* shift out the fraction to make room for the leading zeros */
			int numFractionZeros = 0;
			if (pos + 2 < maxPrintLen)
			{
				int maxFractionZeros, digitsStartIdx, maxFractionDigits, i;

				maxFractionZeros = maxPrintLen - 2 - pos;
				numFractionZeros = -(printExponent + 1);
				if (numFractionZeros > maxFractionZeros)
				{
					numFractionZeros = maxFractionZeros;
				}

				digitsStartIdx = 2 + numFractionZeros;


				// * shift the significant digits right such that there is room for
				// * leading zeros
				// */
				numFractionDigits = numDigits;
				maxFractionDigits = maxPrintLen - digitsStartIdx - pos;
				if (numFractionDigits > maxFractionDigits)
				{
					numFractionDigits = maxFractionDigits;
				}

				movemem(buffer + pos + digitsStartIdx, buffer + pos,
					numFractionDigits);

				/* insert the leading zeros */
				for (i = 2; i < digitsStartIdx; ++i)
				{
					buffer[pos + i] = '0';
				}

				/* update the counts */
				numFractionDigits += numFractionZeros;
				numDigits = numFractionDigits;
			}

			/* add the decimal point */
			if (pos + 1 < maxPrintLen)
			{
				buffer[pos + 1] = '.';
			}

			/* add the initial zero */
			if (pos < maxPrintLen)
			{
				buffer[pos] = '0';
				numDigits += 1;
			}
			numWholeDigits = 1;
			pos += 2 + numFractionDigits;
		}

		/* always add decimal point, except for DprZeros mode */
		if (trim_mode != TrimMode_DptZeros && numFractionDigits == 0 &&
			pos < maxPrintLen)
		{
			buffer[pos++] = '.';
		}

		add_digits = digit_mode == DigitMode_Unique ? min_digits : precision;
		desiredFractionalDigits = add_digits < 0 ? 0 : add_digits;
		if (cutoff_mode == CutoffMode_TotalLength)
		{
			desiredFractionalDigits = add_digits - numWholeDigits;
		}

		if (trim_mode == TrimMode_LeaveOneZero)
		{
			/* if we didn't print any fractional digits, add a trailing 0 */
			if (numFractionDigits == 0 && pos < maxPrintLen)
			{
				buffer[pos++] = '0';
				numFractionDigits++;
			}
		}
		else if (trim_mode == TrimMode_None &&
			desiredFractionalDigits > numFractionDigits &&
			pos < maxPrintLen)
		{
			/* add trailing zeros up to add_digits length */
			/* compute the number of trailing zeros needed */
			int count = desiredFractionalDigits - numFractionDigits;
			if (pos + count > maxPrintLen)
			{
				count = maxPrintLen - pos;
			}
			numFractionDigits += count;

			for (; count > 0; count--)
			{
				buffer[pos++] = '0';
			}
		}
		/* else, for trim_mode Zeros or DptZeros, there is nothing more to add */


		// * when rounding, we may still end up with trailing zeros. Remove them
		// * depending on trim settings.
		// */
		if (trim_mode != TrimMode_None && numFractionDigits > 0)
		{
			while (buffer[pos - 1] == '0')
			{
				pos--;
				numFractionDigits--;
			}
			if (buffer[pos - 1] == '.')
			{
				/* in TrimMode_LeaveOneZero, add trailing 0 back */
				if (trim_mode == TrimMode_LeaveOneZero) {
					buffer[pos++] = '0';
					numFractionDigits++;
				}
				/* in TrimMode_DptZeros, remove trailing decimal point */
				else if (trim_mode == TrimMode_DptZeros)
				{
					pos--;
				}
			}
		}

		/* add any whitespace padding to right side */
		if (digits_right >= numFractionDigits)
		{
			int count = digits_right - numFractionDigits;

			/* in trim_mode DptZeros, if right padding, add a space for the . */
			if (trim_mode == TrimMode_DptZeros && numFractionDigits == 0
				&& pos < maxPrintLen)
			{
				buffer[pos++] = ' ';
			}

			if (pos + count > maxPrintLen)
			{
				count = maxPrintLen - pos;
			}

			for (; count > 0; count--)
			{
				buffer[pos++] = ' ';
			}
		}
		/* add any whitespace padding to left side */
		if (digits_left > numWholeDigits + has_sign)
		{
			int shift = digits_left - (numWholeDigits + has_sign);
			int count = pos;

			if (count + shift > maxPrintLen)
			{
				count = maxPrintLen - shift;
			}

			if (count > 0)
			{
				movemem(buffer + shift, buffer, count);
			}
			pos = shift + count;
			for (; shift > 0; shift--)
			{
				buffer[shift - 1] = ' ';
			}
		}

		/* terminate the buffer */
		buffer[pos] = '\0';

		return pos;
	}


	// * Outputs the positive number with scientific notation: d.dddde[sign]ddd
	// * The output is always NUL terminated and the output length (not including the
	// * NUL) is returned.
	// *
	// * Arguments:
	// *	buffer - buffer to output into
	// *	bufferSize - maximum characters that can be printed to buffer
	// *	mantissa - value significand
	// *	exponent - value exponent in base 2
	// *	signbit - value of the sign position. Should be '+', '-' or ''
	// *	mantissaBit - index of the highest set mantissa bit
	// *	hasUnequalMargins - is the high margin twice as large as the low margin
	// *
	// * See Options for description of remaining arguments.
	// */
	static unsigned int FormatScientific(char* buffer, unsigned int bufferSize, BigInt* mantissa,
		int exponent, char signbit, unsigned int mantissaBit,
		int hasUnequalMargins, DigitMode digit_mode,
		int precision, int min_digits, TrimMode trim_mode,
		int digits_left, int exp_digits)
	{
		int printExponent;
		int numDigits;
		char* pCurOut;
		int numFractionDigits;
		int leftchars;
		int add_digits;

		pCurOut = buffer;

		/* add any whitespace padding to left side */
		leftchars = 1 + (signbit == '-' || signbit == '+');
		if (digits_left > leftchars)
		{
			int i;
			for (i = 0; i < digits_left - leftchars && bufferSize > 1; i++)
			{
				*pCurOut = ' ';
				pCurOut++;
				--bufferSize;
			}
		}

		if (signbit == '+' && bufferSize > 1)
		{
			*pCurOut = '+';
			pCurOut++;
			--bufferSize;
		}
		else if (signbit == '-' && bufferSize > 1)
		{
			*pCurOut = '-';
			pCurOut++;
			--bufferSize;
		}

		numDigits = Dragon4(mantissa, exponent, mantissaBit, hasUnequalMargins,
			digit_mode, CutoffMode_TotalLength,
			precision < 0 ? -1 : precision + 1,
			min_digits < 0 ? -1 : min_digits + 1,
			pCurOut, bufferSize, & printExponent);

		/* keep the whole number as the first digit */
		if (bufferSize > 1)
		{
			pCurOut += 1;
			bufferSize -= 1;
		}

		/* insert the decimal point prior to the fractional number */
		numFractionDigits = numDigits - 1;
		if (numFractionDigits > 0 && bufferSize > 1)
		{
			int maxFractionDigits = (int)bufferSize - 2;

			if (numFractionDigits > maxFractionDigits)
			{
				numFractionDigits = maxFractionDigits;
			}

			movemem(pCurOut + 1, pCurOut, numFractionDigits);
			pCurOut[0] = '.';
			pCurOut += (1 + numFractionDigits);
			bufferSize -= (1 + numFractionDigits);
		}

		/* always add decimal point, except for DprZeros mode */
		if (trim_mode != TrimMode_DptZeros && numFractionDigits == 0 &&
			bufferSize > 1)
		{
			*pCurOut = '.';
			++pCurOut;
			--bufferSize;
		}

		add_digits = digit_mode == DigitMode_Unique ? min_digits : precision;
		add_digits = add_digits < 0 ? 0 : add_digits;
		if (trim_mode == TrimMode_LeaveOneZero)
		{
			/* if we didn't print any fractional digits, add the 0 */
			if (numFractionDigits == 0 && bufferSize > 1)
			{
				*pCurOut = '0';
				++pCurOut;
				--bufferSize;
				++numFractionDigits;
			}
		}
		else if (trim_mode == TrimMode_None)
		{
			/* add trailing zeros up to add_digits length */
			if (add_digits > (int)numFractionDigits)
			{
				char* pEnd;
				/* compute the number of trailing zeros needed */
				int numZeros = (add_digits - numFractionDigits);

				if (numZeros > (int)bufferSize - 1)
				{
					numZeros = (int)bufferSize - 1;
				}

				for (pEnd = pCurOut + numZeros; pCurOut < pEnd; ++pCurOut)
				{
					*pCurOut = '0';
					++numFractionDigits;
				}
			}
		}
		/* else, for trim_mode Zeros or DptZeros, there is nothing more to add */


		// * when rounding, we may still end up with trailing zeros. Remove them
		// * depending on trim settings.
		// */
		if (trim_mode != TrimMode_None && numFractionDigits > 0)
		{
			--pCurOut;
			while (*pCurOut == '0')
			{
				--pCurOut;
				++bufferSize;
				--numFractionDigits;
			}
			if (trim_mode == TrimMode_LeaveOneZero && *pCurOut == '.')
			{
				++pCurOut;
				*pCurOut = '0';
				--bufferSize;
				++numFractionDigits;
			}
			++pCurOut;
		}

		/* print the exponent into a local buffer and copy into output buffer */
		if (bufferSize > 1)
		{
			char exponentBuffer[7];
			int digits[5];
			int i, exp_size, count;

			if (exp_digits > 5)
			{
				exp_digits = 5;
			}
			if (exp_digits < 0)
			{
				exp_digits = 2;
			}

			exponentBuffer[0] = 'e';
			if (printExponent >= 0)
			{
				exponentBuffer[1] = '+';
			}
			else
			{
				exponentBuffer[1] = '-';
				printExponent = -printExponent;
			}

			/* get exp digits */
			for (i = 0; i < 5; i++)
			{
				digits[i] = printExponent % 10;
				printExponent /= 10;
			}
			/* count back over leading zeros */
			for (i = 5; i > exp_digits && digits[i - 1] == 0; i--)
			{
			}
			exp_size = i;
			/* write remaining digits to tmp buf */
			for (i = exp_size; i > 0; i--)
			{
				exponentBuffer[2 + (exp_size - i)] = (char)('0' + digits[i - 1]);
			}

			/* copy the exponent buffer into the output */
			count = exp_size + 2;
			if (count > (int)bufferSize - 1)
			{
				count = (int)bufferSize - 1;
			}
			movemem(pCurOut, exponentBuffer, count);
			pCurOut += count;
			bufferSize -= count;
		}


		pCurOut[0] = '\0';

		return pCurOut - buffer;
	}


	// * Print special case values for infinities and NaNs.
	// * The output string is always NUL terminated and the string length (not
	// * including the NUL) is returned.
	// */
	static unsigned int PrintInfNan(char* buffer, unsigned int bufferSize, unsigned long long mantissa, unsigned int mantissaHexWidth, char signbit)
	{
		unsigned int maxPrintLen = bufferSize - 1;
		unsigned int pos = 0;

		/* Check for infinity */
		if (mantissa == 0)
		{
			unsigned int printLen;

			/* only print sign for inf values (though nan can have a sign set) */
			if (signbit == '+')
			{
				if (pos < maxPrintLen - 1)
				{
					buffer[pos++] = '+';
				}
			}
			else if (signbit == '-')
			{
				if (pos < maxPrintLen - 1)
				{
					buffer[pos++] = '-';
				}
			}

			/* copy and make sure the buffer is terminated */
			printLen = (3 < maxPrintLen - pos) ? 3 : maxPrintLen - pos;
			movemem(buffer + pos, "inf", printLen);
			buffer[pos + printLen] = '\0';
			return pos + printLen;
		}
		else
		{
			/* copy and make sure the buffer is terminated */
			unsigned int printLen = (3 < maxPrintLen - pos) ? 3 : maxPrintLen - pos;
			movemem(buffer + pos, "nan", printLen);
			buffer[pos + printLen] = '\0';

			return pos + printLen;
		}
	}


	// * The functions below format a floating-point numbers stored in particular
	// * formats,  as a decimal string.  The output string is always NUL terminated
	// * and the string length (not including the NUL) is returned.
	// *
	// * For 16, 32 and 64 bit floats we assume they are the IEEE 754 type.
	// * For 128 bit floats we account for different definitions.
	// *
	// * Arguments are:
	// *   buffer - buffer to output into
	// *   bufferSize - maximum characters that can be printed to buffer
	// *   value - value to print
	// *   opt - Dragon4 options, see above
	// */


	// * Helper function that takes Dragon4 parameters and options and
	// * calls Dragon4.
	// */
	static unsigned int Format_floatbits(char* buffer, unsigned int bufferSize, BigInt* mantissa,
		int exponent, char signbit, unsigned int mantissaBit,
		int hasUnequalMargins, const Options* opt)
	{
		/* format the value */
		if (opt->scientific)
		{
			return FormatScientific(buffer, bufferSize, mantissa, exponent,
				signbit, mantissaBit, hasUnequalMargins,
				opt->digit_mode, opt->precision,
				opt->min_digits, opt->trim_mode,
				opt->digits_left, opt->exp_digits);
		}
		else
		{
			return FormatPositional(buffer, bufferSize, mantissa, exponent,
				signbit, mantissaBit, hasUnequalMargins,
				opt->digit_mode, opt->cutoff_mode,
				opt->precision, opt->min_digits, opt->trim_mode,
				opt->digits_left, opt->digits_right);
		}
	}


	// * IEEE binary32 floating-point format
	// *
	// * sign:	  1 bit
	// * exponent:  8 bits
	// * mantissa: 23 bits
	// */
	unsigned int PrintFloat_IEEE_binary(Scratch* scratch, float value, const Options* opt)
	{
		const unsigned int bufferSize = sizeof(scratch->repr);
		BigInt* bigints = scratch->bigints;

		union
		{
			float floatingPoint;
			unsigned int integer;
		} floatUnion;
		unsigned int floatExponent, floatMantissa, floatSign;

		unsigned int mantissa;
		int exponent;
		unsigned int mantissaBit;
		int hasUnequalMargins;
		char signbit = '\0';

		/* deconstruct the floating point value */
		floatUnion.floatingPoint = value;
		floatMantissa = floatUnion.integer & bitmask_u32(23);
		floatExponent = (floatUnion.integer >> 23) & bitmask_u32(8);
		floatSign = floatUnion.integer >> 31;

		/* output the sign */
		if (floatSign != 0)
		{
			signbit = '-';
		}
		else if (opt->sign)
		{
			signbit = '+';
		}

		/* if this is a special value */
		if (floatExponent == bitmask_u32(8))
		{
			return PrintInfNan(scratch->repr, bufferSize, floatMantissa, 6, signbit);
		}
		/* else this is a number */

		/* factor the value into its parts */
		if (floatExponent != 0)
		{

			// * normalized
			// * The floating point equation is:
			// *  value = (1 + mantissa/2^23) * 2 ^ (exponent-127)
			// * We convert the integer equation by factoring a 2^23 out of the
			// * exponent
			// *  value = (1 + mantissa/2^23) * 2^23 * 2 ^ (exponent-127-23)
			// *  value = (2^23 + mantissa) * 2 ^ (exponent-127-23)
			// * Because of the implied 1 in front of the mantissa we have 24 bits of
			// * precision.
			// *   m = (2^23 + mantissa)
			// *   e = (exponent-127-23)
			// */
			mantissa = (1UL << 23) | floatMantissa;
			exponent = floatExponent - 127 - 23;
			mantissaBit = 23;
			hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
		}
		else
		{

			// * denormalized
			// * The floating point equation is:
			// *  value = (mantissa/2^23) * 2 ^ (1-127)
			// * We convert the integer equation by factoring a 2^23 out of the
			// * exponent
			// *  value = (mantissa/2^23) * 2^23 * 2 ^ (1-127-23)
			// *  value = mantissa * 2 ^ (1-127-23)
			// * We have up to 23 bits of precision.
			// *   m = (mantissa)
			// *   e = (1-127-23)
			// */
			mantissa = floatMantissa;
			exponent = 1 - 127 - 23;
			mantissaBit = LogBase2_32(mantissa);
			hasUnequalMargins = false;
		}

		BigInt_Set_uint32(&bigints[0], mantissa);
		return Format_floatbits(scratch->repr, bufferSize, bigints, exponent, signbit, mantissaBit, hasUnequalMargins, opt);
	}


	// * IEEE binary64 floating-point format
	// *
	// * sign:	  1 bit
	// * exponent: 11 bits
	// * mantissa: 52 bits
	// */
	unsigned int PrintFloat_IEEE_binary(Scratch* scratch, const double& value, const Options* opt)
	{
		const unsigned int bufferSize = sizeof(scratch->repr);
		BigInt* bigints = scratch->bigints;

		union
		{
			double floatingPoint;
			unsigned long long integer;
		} floatUnion;
		unsigned int floatExponent, floatSign;
		unsigned long long floatMantissa;

		unsigned long long mantissa;
		int exponent;
		unsigned int mantissaBit;
		int hasUnequalMargins;
		char signbit = '\0';


		/* deconstruct the floating point value */
		floatUnion.floatingPoint = value;
		floatMantissa = floatUnion.integer & bitmask_u64(52);
		floatExponent = (floatUnion.integer >> 52) & bitmask_u32(11);
		floatSign = floatUnion.integer >> 63;

		/* output the sign */
		if (floatSign != 0)
		{
			signbit = '-';
		}
		else if (opt->sign)
		{
			signbit = '+';
		}

		/* if this is a special value */
		if (floatExponent == bitmask_u32(11))
		{
			return PrintInfNan(scratch->repr, bufferSize, floatMantissa, 13, signbit);
		}
		/* else this is a number */

		/* factor the value into its parts */
		if (floatExponent != 0)
		{

			// * normal
			// * The floating point equation is:
			// *  value = (1 + mantissa/2^52) * 2 ^ (exponent-1023)
			// * We convert the integer equation by factoring a 2^52 out of the
			// * exponent
			// *  value = (1 + mantissa/2^52) * 2^52 * 2 ^ (exponent-1023-52)
			// *  value = (2^52 + mantissa) * 2 ^ (exponent-1023-52)
			// * Because of the implied 1 in front of the mantissa we have 53 bits of
			// * precision.
			// *   m = (2^52 + mantissa)
			// *   e = (exponent-1023+1-53)
			// */
			mantissa = (1ull << 52) | floatMantissa;
			exponent = floatExponent - 1023 - 52;
			mantissaBit = 52;
			hasUnequalMargins = (floatExponent != 1) && (floatMantissa == 0);
		}
		else
		{

			// * subnormal
			// * The floating point equation is:
			// *  value = (mantissa/2^52) * 2 ^ (1-1023)
			// * We convert the integer equation by factoring a 2^52 out of the
			// * exponent
			// *  value = (mantissa/2^52) * 2^52 * 2 ^ (1-1023-52)
			// *  value = mantissa * 2 ^ (1-1023-52)
			// * We have up to 52 bits of precision.
			// *   m = (mantissa)
			// *   e = (1-1023-52)
			// */
			mantissa = floatMantissa;
			exponent = 1 - 1023 - 52;
			mantissaBit = LogBase2_64(mantissa);
			hasUnequalMargins = false;
		}

		BigInt_Set_uint64(&bigints[0], mantissa);
		return Format_floatbits(scratch->repr, bufferSize, bigints, exponent, signbit, mantissaBit, hasUnequalMargins, opt);
	}

}

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE