int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken)
{
- bool HasDecimalOrExponent = false;
- int isDouble = 0;
-
const auto saveName = [&](int ch) {
if (len <= MaxTokenLength)
ppToken->name[len++] = static_cast<char>(ch);
};
- // Decimal:
+ // find the range of non-zero digits before the decimal point
+ int startNonZero = 0;
+ while (startNonZero < len && ppToken->name[startNonZero] == '0')
+ ++startNonZero;
+ int endNonZero = len;
+ while (endNonZero > startNonZero && ppToken->name[endNonZero-1] == '0')
+ --endNonZero;
+ int numWholeNumberDigits = endNonZero - startNonZero;
+
+ // accumulate the range's value
+ bool fastPath = numWholeNumberDigits <= 15; // when the number gets too complex, set to false
+ unsigned long long wholeNumber = 0;
+ if (fastPath) {
+ for (int i = startNonZero; i < endNonZero; ++i)
+ wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
+ }
+ int decimalShift = len - endNonZero;
+ // Decimal point:
+ bool hasDecimalOrExponent = false;
if (ch == '.') {
- HasDecimalOrExponent = true;
+ hasDecimalOrExponent = true;
saveName(ch);
ch = getChar();
+ int firstDecimal = len;
// 1.#INF or -1.#INF
if (ch == '#' && (ifdepth > 0 || parseContext.intermediate.getSource() == EShSourceHlsl)) {
}
}
+ // Consume leading-zero digits after the decimal point
+ while (ch == '0') {
+ saveName(ch);
+ ch = getChar();
+ }
+ int startNonZeroDecimal = len;
+ int endNonZeroDecimal = len;
+
+ // Consume remaining digits, up to the exponent
while (ch >= '0' && ch <= '9') {
saveName(ch);
+ if (ch != '0')
+ endNonZeroDecimal = len;
ch = getChar();
}
+
+ // Compute accumulation up to the last non-zero digit
+ if (endNonZeroDecimal > startNonZeroDecimal) {
+ numWholeNumberDigits += endNonZeroDecimal - endNonZero - 1; // don't include the "."
+ if (numWholeNumberDigits > 15)
+ fastPath = false;
+ if (fastPath) {
+ for (int i = endNonZero; i < endNonZeroDecimal; ++i) {
+ if (ppToken->name[i] != '.')
+ wholeNumber = wholeNumber * 10 + (ppToken->name[i] - '0');
+ }
+ }
+ decimalShift = firstDecimal - endNonZeroDecimal;
+ }
}
// Exponent:
-
- if (ch == 'e' || ch == 'E') {
- HasDecimalOrExponent = true;
- saveName(ch);
- ch = getChar();
- if (ch == '+' || ch == '-') {
+ bool negativeExponent = false;
+ double exponentValue = 0.0;
+ int exponent = 0;
+ {
+ if (ch == 'e' || ch == 'E') {
+ hasDecimalOrExponent = true;
saveName(ch);
ch = getChar();
- }
- if (ch >= '0' && ch <= '9') {
- while (ch >= '0' && ch <= '9') {
+ if (ch == '+' || ch == '-') {
+ negativeExponent = ch == '-';
saveName(ch);
ch = getChar();
}
- } else {
- parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
+ if (ch >= '0' && ch <= '9') {
+ while (ch >= '0' && ch <= '9') {
+ exponent = exponent * 10 + (ch - '0');
+ saveName(ch);
+ ch = getChar();
+ }
+ } else {
+ parseContext.ppError(ppToken->loc, "bad character in float exponent", "", "");
+ }
+ }
+
+ // Compensate for location of decimal
+ if (negativeExponent)
+ exponent -= decimalShift;
+ else {
+ exponent += decimalShift;
+ if (exponent < 0) {
+ negativeExponent = true;
+ exponent = -exponent;
+ }
+ }
+ if (exponent > 22)
+ fastPath = false;
+
+ if (fastPath) {
+ // Compute the floating-point value of the exponent
+ exponentValue = 1.0;
+ if (exponent > 0) {
+ double expFactor = 10;
+ while (exponent > 0) {
+ if (exponent & 0x1)
+ exponentValue *= expFactor;
+ expFactor *= expFactor;
+ exponent >>= 1;
+ }
+ }
}
}
// Suffix:
+ bool isDouble = false;
bool isFloat16 = false;
if (ch == 'l' || ch == 'L') {
if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
parseContext.doubleCheck(ppToken->loc, "double floating-point suffix");
- if (ifdepth == 0 && !HasDecimalOrExponent)
+ if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (parseContext.intermediate.getSource() == EShSourceGlsl) {
int ch2 = getChar();
} else {
saveName(ch);
saveName(ch2);
- isDouble = 1;
+ isDouble = true;
}
} else if (parseContext.intermediate.getSource() == EShSourceHlsl) {
saveName(ch);
- isDouble = 1;
+ isDouble = true;
}
} else if (ch == 'h' || ch == 'H') {
if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl)
parseContext.float16Check(ppToken->loc, "half floating-point suffix");
- if (ifdepth == 0 && !HasDecimalOrExponent)
+ if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
if (parseContext.intermediate.getSource() == EShSourceGlsl) {
int ch2 = getChar();
parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix");
if (ifdepth == 0 && !parseContext.relaxedErrors())
parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix");
- if (ifdepth == 0 && !HasDecimalOrExponent)
+ if (ifdepth == 0 && !hasDecimalOrExponent)
parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", "");
saveName(ch);
} else
ungetChar();
- // Patch up the name, length, etc.
+ // Patch up the name and length for overflow
if (len > MaxTokenLength) {
len = MaxTokenLength;
}
ppToken->name[len] = '\0';
- // Get the numerical value
- ppToken->dval = strtod(ppToken->name, nullptr);
+ // Compute the numerical value
+ if (fastPath) {
+ // compute the floating-point value of the exponent
+ if (exponentValue == 0.0)
+ ppToken->dval = (double)wholeNumber;
+ else if (negativeExponent)
+ ppToken->dval = (double)wholeNumber / exponentValue;
+ else
+ ppToken->dval = (double)wholeNumber * exponentValue;
+ } else {
+ // slow path
+ strtodStream.clear();
+ strtodStream.str(ppToken->name);
+ strtodStream >> ppToken->dval;
+ // Assume failure combined with a large exponent was overflow, in
+ // an attempt to set INF. Otherwise, assume underflow, and set 0.0.
+ if (strtodStream.fail()) {
+ if (!negativeExponent && exponent + numWholeNumberDigits > 300)
+ ppToken->i64val = 0x7ff0000000000000; // +Infinity
+ else
+ ppToken->dval = 0.0;
+ }
+ }
// Return the right token type
if (isDouble)