PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/icu-small/source/i18n/precision.cpp

https://gitlab.com/CORP-RESELLER/node
C++ | 442 lines | 388 code | 33 blank | 21 comment | 77 complexity | 10cadeb285e4bbb5ebed74e036273954 MD5 | raw file
  1. /*
  2. * Copyright (C) 2015, International Business Machines
  3. * Corporation and others. All Rights Reserved.
  4. *
  5. * file name: precisison.cpp
  6. */
  7. #include <math.h>
  8. #include "unicode/utypes.h"
  9. #if !UCONFIG_NO_FORMATTING
  10. #include "digitlst.h"
  11. #include "fmtableimp.h"
  12. #include "precision.h"
  13. #include "putilimp.h"
  14. #include "visibledigits.h"
  15. U_NAMESPACE_BEGIN
  16. static const int32_t gPower10[] = {1, 10, 100, 1000};
  17. FixedPrecision::FixedPrecision()
  18. : fExactOnly(FALSE), fFailIfOverMax(FALSE), fRoundingMode(DecimalFormat::kRoundHalfEven) {
  19. fMin.setIntDigitCount(1);
  20. fMin.setFracDigitCount(0);
  21. }
  22. UBool
  23. FixedPrecision::isRoundingRequired(
  24. int32_t upperExponent, int32_t lowerExponent) const {
  25. int32_t leastSigAllowed = fMax.getLeastSignificantInclusive();
  26. int32_t maxSignificantDigits = fSignificant.getMax();
  27. int32_t roundDigit;
  28. if (maxSignificantDigits == INT32_MAX) {
  29. roundDigit = leastSigAllowed;
  30. } else {
  31. int32_t limitDigit = upperExponent - maxSignificantDigits;
  32. roundDigit =
  33. limitDigit > leastSigAllowed ? limitDigit : leastSigAllowed;
  34. }
  35. return (roundDigit > lowerExponent);
  36. }
  37. DigitList &
  38. FixedPrecision::round(
  39. DigitList &value, int32_t exponent, UErrorCode &status) const {
  40. if (U_FAILURE(status)) {
  41. return value;
  42. }
  43. value .fContext.status &= ~DEC_Inexact;
  44. if (!fRoundingIncrement.isZero()) {
  45. if (exponent == 0) {
  46. value.quantize(fRoundingIncrement, status);
  47. } else {
  48. DigitList adjustedIncrement(fRoundingIncrement);
  49. adjustedIncrement.shiftDecimalRight(exponent);
  50. value.quantize(adjustedIncrement, status);
  51. }
  52. if (U_FAILURE(status)) {
  53. return value;
  54. }
  55. }
  56. int32_t leastSig = fMax.getLeastSignificantInclusive();
  57. if (leastSig == INT32_MIN) {
  58. value.round(fSignificant.getMax());
  59. } else {
  60. value.roundAtExponent(
  61. exponent + leastSig,
  62. fSignificant.getMax());
  63. }
  64. if (fExactOnly && (value.fContext.status & DEC_Inexact)) {
  65. status = U_FORMAT_INEXACT_ERROR;
  66. } else if (fFailIfOverMax) {
  67. // Smallest interval for value stored in interval
  68. DigitInterval interval;
  69. value.getSmallestInterval(interval);
  70. if (fMax.getIntDigitCount() < interval.getIntDigitCount()) {
  71. status = U_ILLEGAL_ARGUMENT_ERROR;
  72. }
  73. }
  74. return value;
  75. }
  76. DigitInterval &
  77. FixedPrecision::getIntervalForZero(DigitInterval &interval) const {
  78. interval = fMin;
  79. if (fSignificant.getMin() > 0) {
  80. interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
  81. }
  82. interval.shrinkToFitWithin(fMax);
  83. return interval;
  84. }
  85. DigitInterval &
  86. FixedPrecision::getInterval(
  87. int32_t upperExponent, DigitInterval &interval) const {
  88. if (fSignificant.getMin() > 0) {
  89. interval.expandToContainDigit(
  90. upperExponent - fSignificant.getMin());
  91. }
  92. interval.expandToContain(fMin);
  93. interval.shrinkToFitWithin(fMax);
  94. return interval;
  95. }
  96. DigitInterval &
  97. FixedPrecision::getInterval(
  98. const DigitList &value, DigitInterval &interval) const {
  99. if (value.isZero()) {
  100. interval = fMin;
  101. if (fSignificant.getMin() > 0) {
  102. interval.expandToContainDigit(interval.getIntDigitCount() - fSignificant.getMin());
  103. }
  104. } else {
  105. value.getSmallestInterval(interval);
  106. if (fSignificant.getMin() > 0) {
  107. interval.expandToContainDigit(
  108. value.getUpperExponent() - fSignificant.getMin());
  109. }
  110. interval.expandToContain(fMin);
  111. }
  112. interval.shrinkToFitWithin(fMax);
  113. return interval;
  114. }
  115. UBool
  116. FixedPrecision::isFastFormattable() const {
  117. return (fMin.getFracDigitCount() == 0 && fSignificant.isNoConstraints() && fRoundingIncrement.isZero() && !fFailIfOverMax);
  118. }
  119. UBool
  120. FixedPrecision::handleNonNumeric(DigitList &value, VisibleDigits &digits) {
  121. if (value.isNaN()) {
  122. digits.setNaN();
  123. return TRUE;
  124. }
  125. if (value.isInfinite()) {
  126. digits.setInfinite();
  127. if (!value.isPositive()) {
  128. digits.setNegative();
  129. }
  130. return TRUE;
  131. }
  132. return FALSE;
  133. }
  134. VisibleDigits &
  135. FixedPrecision::initVisibleDigits(
  136. DigitList &value,
  137. VisibleDigits &digits,
  138. UErrorCode &status) const {
  139. if (U_FAILURE(status)) {
  140. return digits;
  141. }
  142. digits.clear();
  143. if (handleNonNumeric(value, digits)) {
  144. return digits;
  145. }
  146. if (!value.isPositive()) {
  147. digits.setNegative();
  148. }
  149. value.setRoundingMode(fRoundingMode);
  150. round(value, 0, status);
  151. getInterval(value, digits.fInterval);
  152. digits.fExponent = value.getLowerExponent();
  153. value.appendDigitsTo(digits.fDigits, status);
  154. return digits;
  155. }
  156. VisibleDigits &
  157. FixedPrecision::initVisibleDigits(
  158. int64_t value,
  159. VisibleDigits &digits,
  160. UErrorCode &status) const {
  161. if (U_FAILURE(status)) {
  162. return digits;
  163. }
  164. if (!fRoundingIncrement.isZero()) {
  165. // If we have round increment, use digit list.
  166. DigitList digitList;
  167. digitList.set(value);
  168. return initVisibleDigits(digitList, digits, status);
  169. }
  170. // Try fast path
  171. if (initVisibleDigits(value, 0, digits, status)) {
  172. digits.fAbsDoubleValue = fabs((double) value);
  173. digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
  174. return digits;
  175. }
  176. // Oops have to use digit list
  177. DigitList digitList;
  178. digitList.set(value);
  179. return initVisibleDigits(digitList, digits, status);
  180. }
  181. VisibleDigits &
  182. FixedPrecision::initVisibleDigits(
  183. double value,
  184. VisibleDigits &digits,
  185. UErrorCode &status) const {
  186. if (U_FAILURE(status)) {
  187. return digits;
  188. }
  189. digits.clear();
  190. if (uprv_isNaN(value)) {
  191. digits.setNaN();
  192. return digits;
  193. }
  194. if (uprv_isPositiveInfinity(value)) {
  195. digits.setInfinite();
  196. return digits;
  197. }
  198. if (uprv_isNegativeInfinity(value)) {
  199. digits.setInfinite();
  200. digits.setNegative();
  201. return digits;
  202. }
  203. if (!fRoundingIncrement.isZero()) {
  204. // If we have round increment, use digit list.
  205. DigitList digitList;
  206. digitList.set(value);
  207. return initVisibleDigits(digitList, digits, status);
  208. }
  209. // Try to find n such that value * 10^n is an integer
  210. int32_t n = -1;
  211. double scaled;
  212. for (int32_t i = 0; i < UPRV_LENGTHOF(gPower10); ++i) {
  213. scaled = value * gPower10[i];
  214. if (scaled > MAX_INT64_IN_DOUBLE || scaled < -MAX_INT64_IN_DOUBLE) {
  215. break;
  216. }
  217. if (scaled == floor(scaled)) {
  218. n = i;
  219. break;
  220. }
  221. }
  222. // Try fast path
  223. if (n >= 0 && initVisibleDigits(scaled, -n, digits, status)) {
  224. digits.fAbsDoubleValue = fabs(value);
  225. digits.fAbsDoubleValueSet = U_SUCCESS(status) && !digits.isOverMaxDigits();
  226. // Adjust for negative 0 becuase when we cast to an int64,
  227. // negative 0 becomes positive 0.
  228. if (scaled == 0.0 && uprv_isNegative(scaled)) {
  229. digits.setNegative();
  230. }
  231. return digits;
  232. }
  233. // Oops have to use digit list
  234. DigitList digitList;
  235. digitList.set(value);
  236. return initVisibleDigits(digitList, digits, status);
  237. }
  238. UBool
  239. FixedPrecision::initVisibleDigits(
  240. int64_t mantissa,
  241. int32_t exponent,
  242. VisibleDigits &digits,
  243. UErrorCode &status) const {
  244. if (U_FAILURE(status)) {
  245. return TRUE;
  246. }
  247. digits.clear();
  248. // Precompute fAbsIntValue if it is small enough, but we don't know yet
  249. // if it will be valid.
  250. UBool absIntValueComputed = FALSE;
  251. if (mantissa > -1000000000000000000LL /* -1e18 */
  252. && mantissa < 1000000000000000000LL /* 1e18 */) {
  253. digits.fAbsIntValue = mantissa;
  254. if (digits.fAbsIntValue < 0) {
  255. digits.fAbsIntValue = -digits.fAbsIntValue;
  256. }
  257. int32_t i = 0;
  258. int32_t maxPower10Exp = UPRV_LENGTHOF(gPower10) - 1;
  259. for (; i > exponent + maxPower10Exp; i -= maxPower10Exp) {
  260. digits.fAbsIntValue /= gPower10[maxPower10Exp];
  261. }
  262. digits.fAbsIntValue /= gPower10[i - exponent];
  263. absIntValueComputed = TRUE;
  264. }
  265. if (mantissa == 0) {
  266. getIntervalForZero(digits.fInterval);
  267. digits.fAbsIntValueSet = absIntValueComputed;
  268. return TRUE;
  269. }
  270. // be sure least significant digit is non zero
  271. while (mantissa % 10 == 0) {
  272. mantissa /= 10;
  273. ++exponent;
  274. }
  275. if (mantissa < 0) {
  276. digits.fDigits.append((char) -(mantissa % -10), status);
  277. mantissa /= -10;
  278. digits.setNegative();
  279. }
  280. while (mantissa) {
  281. digits.fDigits.append((char) (mantissa % 10), status);
  282. mantissa /= 10;
  283. }
  284. if (U_FAILURE(status)) {
  285. return TRUE;
  286. }
  287. digits.fExponent = exponent;
  288. int32_t upperExponent = exponent + digits.fDigits.length();
  289. if (fFailIfOverMax && upperExponent > fMax.getIntDigitCount()) {
  290. status = U_ILLEGAL_ARGUMENT_ERROR;
  291. return TRUE;
  292. }
  293. UBool roundingRequired =
  294. isRoundingRequired(upperExponent, exponent);
  295. if (roundingRequired) {
  296. if (fExactOnly) {
  297. status = U_FORMAT_INEXACT_ERROR;
  298. return TRUE;
  299. }
  300. return FALSE;
  301. }
  302. digits.fInterval.setLeastSignificantInclusive(exponent);
  303. digits.fInterval.setMostSignificantExclusive(upperExponent);
  304. getInterval(upperExponent, digits.fInterval);
  305. // The intValue we computed above is only valid if our visible digits
  306. // doesn't exceed the maximum integer digits allowed.
  307. digits.fAbsIntValueSet = absIntValueComputed && !digits.isOverMaxDigits();
  308. return TRUE;
  309. }
  310. VisibleDigitsWithExponent &
  311. FixedPrecision::initVisibleDigitsWithExponent(
  312. DigitList &value,
  313. VisibleDigitsWithExponent &digits,
  314. UErrorCode &status) const {
  315. digits.clear();
  316. initVisibleDigits(value, digits.fMantissa, status);
  317. return digits;
  318. }
  319. VisibleDigitsWithExponent &
  320. FixedPrecision::initVisibleDigitsWithExponent(
  321. double value,
  322. VisibleDigitsWithExponent &digits,
  323. UErrorCode &status) const {
  324. digits.clear();
  325. initVisibleDigits(value, digits.fMantissa, status);
  326. return digits;
  327. }
  328. VisibleDigitsWithExponent &
  329. FixedPrecision::initVisibleDigitsWithExponent(
  330. int64_t value,
  331. VisibleDigitsWithExponent &digits,
  332. UErrorCode &status) const {
  333. digits.clear();
  334. initVisibleDigits(value, digits.fMantissa, status);
  335. return digits;
  336. }
  337. ScientificPrecision::ScientificPrecision() : fMinExponentDigits(1) {
  338. }
  339. DigitList &
  340. ScientificPrecision::round(DigitList &value, UErrorCode &status) const {
  341. if (U_FAILURE(status)) {
  342. return value;
  343. }
  344. int32_t exponent = value.getScientificExponent(
  345. fMantissa.fMin.getIntDigitCount(), getMultiplier());
  346. return fMantissa.round(value, exponent, status);
  347. }
  348. int32_t
  349. ScientificPrecision::toScientific(DigitList &value) const {
  350. return value.toScientific(
  351. fMantissa.fMin.getIntDigitCount(), getMultiplier());
  352. }
  353. int32_t
  354. ScientificPrecision::getMultiplier() const {
  355. int32_t maxIntDigitCount = fMantissa.fMax.getIntDigitCount();
  356. if (maxIntDigitCount == INT32_MAX) {
  357. return 1;
  358. }
  359. int32_t multiplier =
  360. maxIntDigitCount - fMantissa.fMin.getIntDigitCount() + 1;
  361. return (multiplier < 1 ? 1 : multiplier);
  362. }
  363. VisibleDigitsWithExponent &
  364. ScientificPrecision::initVisibleDigitsWithExponent(
  365. DigitList &value,
  366. VisibleDigitsWithExponent &digits,
  367. UErrorCode &status) const {
  368. if (U_FAILURE(status)) {
  369. return digits;
  370. }
  371. digits.clear();
  372. if (FixedPrecision::handleNonNumeric(value, digits.fMantissa)) {
  373. return digits;
  374. }
  375. value.setRoundingMode(fMantissa.fRoundingMode);
  376. int64_t exponent = toScientific(round(value, status));
  377. fMantissa.initVisibleDigits(value, digits.fMantissa, status);
  378. FixedPrecision exponentPrecision;
  379. exponentPrecision.fMin.setIntDigitCount(fMinExponentDigits);
  380. exponentPrecision.initVisibleDigits(exponent, digits.fExponent, status);
  381. digits.fHasExponent = TRUE;
  382. return digits;
  383. }
  384. VisibleDigitsWithExponent &
  385. ScientificPrecision::initVisibleDigitsWithExponent(
  386. double value,
  387. VisibleDigitsWithExponent &digits,
  388. UErrorCode &status) const {
  389. if (U_FAILURE(status)) {
  390. return digits;
  391. }
  392. DigitList digitList;
  393. digitList.set(value);
  394. return initVisibleDigitsWithExponent(digitList, digits, status);
  395. }
  396. VisibleDigitsWithExponent &
  397. ScientificPrecision::initVisibleDigitsWithExponent(
  398. int64_t value,
  399. VisibleDigitsWithExponent &digits,
  400. UErrorCode &status) const {
  401. if (U_FAILURE(status)) {
  402. return digits;
  403. }
  404. DigitList digitList;
  405. digitList.set(value);
  406. return initVisibleDigitsWithExponent(digitList, digits, status);
  407. }
  408. U_NAMESPACE_END
  409. #endif /* #if !UCONFIG_NO_FORMATTING */