Exemple #1
0
void qore_number_private::applyRoundingHeuristic(QoreString& str, qore_size_t dp, qore_size_t last) {
   // if there are some significant digits after the decimal point (signal)
   bool signal = false;
   // the position of the last significant digit
   qore_offset_t pos = (qore_offset_t)dp;
   qore_size_t i = dp;
   // the last digit found in the sequence
   char lc = 0;
   // 0 or 9 count
   unsigned cnt = 0;
   bool has_e = (str[last] == 'e');
   // don't check the last character
   --last;
   // check all except the last digit
   while (i < last) {
      char c = str[i++];
      if (c == '0' || c == '9') {
         // continue the sequence
         if (c == lc) {
            ++cnt;
            continue;
         }

	 // check for 2nd threshold
         if ((i == last) && cnt > QORE_MPFR_ROUND_THRESHOLD_2) {
            break;
         }

         // set last digit to digit found
         lc = c;
         // if first digit, then do not set signal flag
         if (i == (dp + 1))
            continue;
      }
      else {
         // check for 2nd threshold
         if ((i == last) && cnt > QORE_MPFR_ROUND_THRESHOLD_2) {
            break;
         }
         // no 0 or 9 digit found
         lc = 0;
      }

      // mark position of the last significant digit
      pos = i - 2;
      //printd(5, "qore_number_private::applyRoundingHeuristic('%s') set pos: %lld ('%c') dp: %lld\n", str.getBuffer(), pos, str[pos], dp);

      // found a non-noise digit
      if (!signal)
         signal = true;
      // reset count
      cnt = 0;
   }

   // round the number for display
   if (signal && cnt > QORE_MPFR_ROUND_THRESHOLD) {
      //printd(5, "ROUND BEFORE: (pos: %d dp: %d cnt: %d has_e: %d e: %c) %s\n", pos, dp, cnt, has_e, has_e ? str[pos + cnt + 4] : 'x', str.getBuffer());
      // if rounding right after the decimal point, then remove the decimal point
      if (pos == (qore_offset_t)dp)
         --pos;
      if (has_e && str[pos + cnt + 3] == 'e')
	 --cnt;
      // remove the excess digits
      if (!has_e)
         str.terminate(pos + 1);
      else
         str.replace(pos + 1, cnt + 3, (const char*)0);

      // rounding down is easy; the truncation is enough
      if (lc == '9') // round up
         roundUp(str, pos);
      //printd(5, "ROUND AFTER: %s\n", str.getBuffer());
   }
}
Exemple #2
0
int qore_number_private::formatNumberString(QoreString& num, const QoreString& fmt, ExceptionSink* xsink) {
   assert(!num.empty());
   assert(num.getEncoding() == fmt.getEncoding());
   // get the length of the format string in characters (not bytes)
   qore_size_t fl = fmt.length();
   if (fmt.empty() || fl == 2) {
      printd(5, "qore_number_private::formatNumberString() invalid format string: '%s' for number: '%s'\n", fmt.getBuffer(), num.getBuffer());
      return 0;
   }

   // get thousands separator character
   QoreString tsep;
   if (tsep.concat(fmt, 0, 1, xsink))
      return -1;

   // decimal separator
   QoreString dsep;
   // number of digits after the decimal separator
   unsigned prec = 0;
   if (fl > 1) {
      if (dsep.concat(fmt, 1, 1, xsink))
         return -1;
      // get byte offset of start of decimal precision number
      qore_offset_t i = fmt.getByteOffset(2, xsink);
      if (*xsink)
         return -1;
      assert(i >= 2);
      prec = atoi(fmt.getBuffer() + i);
      if (!prec)
         dsep.clear();
   }

   //printd(5, "qore_number_private::formatNumberString() tsep: '%s' dsep: '%s' prec: %d '%s'\n", tsep.getBuffer(), dsep.getBuffer(), prec, num.getBuffer());

   // find decimal point
   qore_offset_t dp = num.find('.');
   if (dp != -1) {
      // how many digits do we have now after the decimal point
      qore_size_t d = num.strlen() - dp - 1;
      assert(d);
      if (d < prec)
         num.addch('0', prec - d);
      else if (d > prec) {
         if ((num[dp + prec + 1] > '4') && (roundUp(num, dp + prec)))
            ++dp;
         num.terminate(dp + prec + 1);
      }
      // now substitute decimal point if necessary
      if (dsep.strlen() != 1 || dsep[0] != '.')
         num.replace(dp, 1, dsep.getBuffer());
   }
   else {
      dp = num.size();
      if (prec) {
         // add decimal point
         num.concat(&dsep, xsink);
         assert(!*xsink);
         // add zeros for significant digits
         num.addch('0', prec);
      }
   }

   // now insert thousands separator
   // start of digits before the decimal point
   qore_offset_t ds = num[0] == '-' ? 1 : 0;

   // work backwards from the decimal point
   qore_offset_t i = dp - 3;
   while (i > ds) {
      num.replace(i, 0, tsep.getBuffer());
      i -= 3;
   }

   //printd(0, "qore_number_private::formatNumberString() ok '%s'\n", num.getBuffer());

   //assert(false); xxx
   return 0;
}