| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- #include "numeric_conversion.h"
- #include <string.h>
- #include "hardware_seam.h"
- #include "program_memory.h"
- namespace meCoffee {
- namespace {
- // binary32 bit patterns for 10^-w and 10^+w with w = 1, 2, 4, 8, 16, 32.
- const uint32_t kNegativeDecimalPowerBitPatterns[6] MECOFFEE_PROGRAM_MEMORY = {
- 0x3dcccccdUL, 0x3c23d70aUL, 0x38d1b717UL, 0x322bcc77UL, 0x24e69595UL, 0x0a4fb11fUL};
- const uint32_t kPositiveDecimalPowerBitPatterns[6] MECOFFEE_PROGRAM_MEMORY = {
- 0x41200000UL, 0x42c80000UL, 0x461c4000UL, 0x4cbebc20UL, 0x5a0e1bcaUL, 0x749dc5aeUL};
- const uint8_t kDecimalPowerWeights[6] = {1, 2, 4, 8, 16, 32};
- constexpr uint32_t kSignificandOverflowThreshold = 429496728UL;
- constexpr uint16_t kExponentDigitFreezeThreshold = 3200;
- constexpr uint32_t kCanonicalNotANumberBitPattern = 0x7fc00000UL;
- constexpr uint32_t kPositiveInfinityBitPattern = 0x7f800000UL;
- float reinterpretBitPatternAsFloat(uint32_t bitPattern) {
- float reinterpretedValue;
- memcpy(&reinterpretedValue, &bitPattern, sizeof reinterpretedValue);
- return reinterpretedValue;
- }
- uint32_t reinterpretFloatAsBitPattern(float numericValue) {
- uint32_t bitPattern;
- memcpy(&bitPattern, &numericValue, sizeof bitPattern);
- return bitPattern;
- }
- uint32_t readProgramMemoryUnsigned32(const uint32_t* programMemoryAddress) {
- const uint8_t* firstByte = reinterpret_cast<const uint8_t*>(programMemoryAddress);
- uint32_t assembledValue = 0;
- for (uint8_t byteIndex = 0; byteIndex < 4; ++byteIndex) {
- assembledValue |= static_cast<uint32_t>(hardware::readProgramMemoryByte(firstByte + byteIndex))
- << (8 * byteIndex);
- }
- return assembledValue;
- }
- bool isWhitespaceCharacter(char character) {
- return character == ' ' || (character >= 0x09 && character <= 0x0d);
- }
- bool isDecimalDigit(char character) { return character >= '0' && character <= '9'; }
- char toLowerCaseLetter(char character) {
- return (character >= 'A' && character <= 'Z') ? static_cast<char>(character + ('a' - 'A')) : character;
- }
- bool startsWithCaseInsensitive(const char* text, const char* lowerCasePrefix) {
- while (*lowerCasePrefix != '\0') {
- if (toLowerCaseLetter(*text) != *lowerCasePrefix) {
- return false;
- }
- ++text;
- ++lowerCasePrefix;
- }
- return true;
- }
- } // namespace
- float parseDecimalFloatingPoint(const char* text, DecimalParseDiagnostics* diagnostics) {
- DecimalParseDiagnostics localDiagnostics = {};
- DecimalParseDiagnostics& recorded = diagnostics != nullptr ? *diagnostics : localDiagnostics;
- recorded = DecimalParseDiagnostics{};
- const char* cursor = text;
- while (isWhitespaceCharacter(*cursor)) {
- ++cursor;
- }
- bool isNegative = false;
- if (*cursor == '-') {
- isNegative = true;
- ++cursor;
- } else if (*cursor == '+') {
- ++cursor;
- }
- if (startsWithCaseInsensitive(cursor, "nan")) {
- recorded.consumedCharacterCount = static_cast<uint16_t>(cursor + 3 - text);
- return reinterpretBitPatternAsFloat(kCanonicalNotANumberBitPattern);
- }
- if (startsWithCaseInsensitive(cursor, "inf")) {
- cursor += 3;
- if (startsWithCaseInsensitive(cursor, "inity")) {
- cursor += 5;
- }
- recorded.consumedCharacterCount = static_cast<uint16_t>(cursor - text);
- return reinterpretBitPatternAsFloat(kPositiveInfinityBitPattern | (isNegative ? 0x80000000UL : 0));
- }
- uint32_t significand = 0;
- uint16_t decimalExponentOffset = 0;
- uint16_t discardedDigitCount = 0;
- bool hasSignificandDigit = false;
- bool hasSeenDecimalPoint = false;
- bool isDiscardingDigits = false;
- for (;; ++cursor) {
- const char character = *cursor;
- if (isDecimalDigit(character)) {
- hasSignificandDigit = true;
- if (isDiscardingDigits) {
- ++discardedDigitCount;
- if (!hasSeenDecimalPoint) {
- ++decimalExponentOffset;
- }
- } else {
- if (hasSeenDecimalPoint) {
- --decimalExponentOffset;
- }
- significand = significand * 10 + static_cast<uint8_t>(character - '0');
- if (significand >= kSignificandOverflowThreshold) {
- isDiscardingDigits = true;
- }
- }
- } else if (character == '.' && !hasSeenDecimalPoint) {
- hasSeenDecimalPoint = true;
- } else {
- break;
- }
- }
- if (!hasSignificandDigit) {
- return 0.0f;
- }
- if (*cursor == 'e' || *cursor == 'E') {
- const char* exponentCursor = cursor + 1;
- bool isExponentNegative = false;
- if (*exponentCursor == '-') {
- isExponentNegative = true;
- ++exponentCursor;
- } else if (*exponentCursor == '+') {
- ++exponentCursor;
- }
- if (isDecimalDigit(*exponentCursor)) {
- uint16_t explicitExponent = 0;
- while (isDecimalDigit(*exponentCursor)) {
- if (explicitExponent < kExponentDigitFreezeThreshold) {
- explicitExponent = static_cast<uint16_t>(explicitExponent * 10 + (*exponentCursor - '0'));
- }
- ++exponentCursor;
- }
- decimalExponentOffset = static_cast<uint16_t>(
- decimalExponentOffset + (isExponentNegative ? static_cast<uint16_t>(0 - explicitExponent) : explicitExponent));
- cursor = exponentCursor;
- }
- }
- recorded.retainedSignificand = significand;
- recorded.decimalExponentOffset = static_cast<int16_t>(decimalExponentOffset);
- recorded.discardedSignificandDigitCount = discardedDigitCount;
- recorded.consumedCharacterCount = static_cast<uint16_t>(cursor - text);
- float scaledValue = static_cast<float>(significand);
- if (isNegative) {
- scaledValue = -scaledValue;
- }
- if (significand == 0) {
- return scaledValue;
- }
- const int16_t signedExponentOffset = static_cast<int16_t>(decimalExponentOffset);
- const bool isScalingDownward = signedExponentOffset < 0;
- uint16_t remainingExponentMagnitude = isScalingDownward
- ? static_cast<uint16_t>(0 - static_cast<uint16_t>(signedExponentOffset))
- : static_cast<uint16_t>(signedExponentOffset);
- const uint32_t* powerTable = isScalingDownward ? kNegativeDecimalPowerBitPatterns : kPositiveDecimalPowerBitPatterns;
- for (int8_t weightIndex = 5; weightIndex >= 0; --weightIndex) {
- const float decimalPower = reinterpretBitPatternAsFloat(readProgramMemoryUnsigned32(&powerTable[weightIndex]));
- while (remainingExponentMagnitude >= kDecimalPowerWeights[weightIndex]) {
- scaledValue *= decimalPower;
- remainingExponentMagnitude = static_cast<uint16_t>(remainingExponentMagnitude - kDecimalPowerWeights[weightIndex]);
- }
- }
- const uint32_t scaledBitPattern = reinterpretFloatAsBitPattern(scaledValue);
- const bool isInfinite = (scaledBitPattern & 0x7fffffffUL) == kPositiveInfinityBitPattern;
- const bool isZero = (scaledBitPattern & 0x7fffffffUL) == 0;
- recorded.isOutOfRangeIndicatorRaised = isInfinite || isZero;
- return scaledValue;
- }
- uint32_t convertFloatToUnsigned32(float numericValue, bool* isConversionStatusFlagged) {
- bool isFlagged = false;
- uint32_t convertedValue = 0;
- const uint32_t bitPattern = reinterpretFloatAsBitPattern(numericValue);
- const bool isNegative = (bitPattern & 0x80000000UL) != 0;
- const uint8_t biasedExponent = static_cast<uint8_t>((bitPattern >> 23) & 0xff);
- if (biasedExponent == 0xff) {
- isFlagged = true;
- } else if (biasedExponent >= 127) {
- const uint8_t unbiasedExponent = static_cast<uint8_t>(biasedExponent - 127);
- if (unbiasedExponent >= 32) {
- isFlagged = true;
- } else {
- const uint32_t significandWithHiddenBit = (bitPattern & 0x007fffffUL) | 0x00800000UL;
- const uint32_t magnitude = unbiasedExponent >= 23
- ? significandWithHiddenBit << (unbiasedExponent - 23)
- : significandWithHiddenBit >> (23 - unbiasedExponent);
- if (magnitude >= 0x80000000UL) {
- isFlagged = true;
- }
- convertedValue = isNegative ? static_cast<uint32_t>(0 - magnitude) : magnitude;
- }
- }
- if (isConversionStatusFlagged != nullptr) {
- *isConversionStatusFlagged = isFlagged;
- }
- return convertedValue;
- }
- int32_t convertFloatToSigned32(float numericValue) {
- bool isFlagged = false;
- const uint32_t convertedValue = convertFloatToUnsigned32(numericValue, &isFlagged);
- if (isFlagged) {
- return INT32_MIN;
- }
- return static_cast<int32_t>(convertedValue);
- }
- namespace {
- uint32_t parseIntegerPrefix(const char* text, uint8_t bitWidth) {
- const char* cursor = text;
- while (isWhitespaceCharacter(*cursor)) {
- ++cursor;
- }
- bool isNegative = false;
- if (*cursor == '-') {
- isNegative = true;
- ++cursor;
- } else if (*cursor == '+') {
- ++cursor;
- }
- uint32_t accumulated = 0;
- while (isDecimalDigit(*cursor)) {
- accumulated = accumulated * 10 + static_cast<uint8_t>(*cursor - '0');
- ++cursor;
- }
- if (isNegative) {
- accumulated = 0 - accumulated;
- }
- return bitWidth == 16 ? (accumulated & 0xffffUL) : accumulated;
- }
- } // namespace
- uint16_t parseIntegerPrefixModulo65536(const char* text) {
- return static_cast<uint16_t>(parseIntegerPrefix(text, 16));
- }
- uint32_t parseIntegerPrefixModulo4294967296(const char* text) { return parseIntegerPrefix(text, 32); }
- uint8_t formatUnsignedDecimal(uint32_t numericValue, char* outputBuffer) {
- char reversedDigits[10];
- uint8_t digitCount = 0;
- do {
- reversedDigits[digitCount++] = static_cast<char>('0' + numericValue % 10);
- numericValue /= 10;
- } while (numericValue != 0);
- for (uint8_t position = 0; position < digitCount; ++position) {
- outputBuffer[position] = reversedDigits[digitCount - 1 - position];
- }
- return digitCount;
- }
- uint8_t formatSignedDecimal(int32_t numericValue, char* outputBuffer) {
- if (numericValue < 0) {
- outputBuffer[0] = '-';
- return static_cast<uint8_t>(1 + formatUnsignedDecimal(0 - static_cast<uint32_t>(numericValue), outputBuffer + 1));
- }
- return formatUnsignedDecimal(static_cast<uint32_t>(numericValue), outputBuffer);
- }
- } // namespace meCoffee
|