DD.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. import StringBuffer from '../../../../java/lang/StringBuffer'
  2. import Double from '../../../../java/lang/Double'
  3. import Integer from '../../../../java/lang/Integer'
  4. import Character from '../../../../java/lang/Character'
  5. import Comparable from '../../../../java/lang/Comparable'
  6. import Cloneable from '../../../../java/lang/Cloneable'
  7. import Serializable from '../../../../java/io/Serializable'
  8. export default class DD {
  9. constructor() {
  10. DD.constructor_.apply(this, arguments)
  11. }
  12. static constructor_() {
  13. this._hi = 0.0
  14. this._lo = 0.0
  15. if (arguments.length === 0) {
  16. this.init(0.0)
  17. } else if (arguments.length === 1) {
  18. if (typeof arguments[0] === 'number') {
  19. const x = arguments[0]
  20. this.init(x)
  21. } else if (arguments[0] instanceof DD) {
  22. const dd = arguments[0]
  23. this.init(dd)
  24. } else if (typeof arguments[0] === 'string') {
  25. const str = arguments[0]
  26. DD.constructor_.call(this, DD.parse(str))
  27. }
  28. } else if (arguments.length === 2) {
  29. const hi = arguments[0], lo = arguments[1]
  30. this.init(hi, lo)
  31. }
  32. }
  33. static determinant() {
  34. if (typeof arguments[3] === 'number' && (typeof arguments[2] === 'number' && (typeof arguments[0] === 'number' && typeof arguments[1] === 'number'))) {
  35. const x1 = arguments[0], y1 = arguments[1], x2 = arguments[2], y2 = arguments[3]
  36. return DD.determinant(DD.valueOf(x1), DD.valueOf(y1), DD.valueOf(x2), DD.valueOf(y2))
  37. } else if (arguments[3] instanceof DD && (arguments[2] instanceof DD && (arguments[0] instanceof DD && arguments[1] instanceof DD))) {
  38. const x1 = arguments[0], y1 = arguments[1], x2 = arguments[2], y2 = arguments[3]
  39. const det = x1.multiply(y2).selfSubtract(y1.multiply(x2))
  40. return det
  41. }
  42. }
  43. static sqr(x) {
  44. return DD.valueOf(x).selfMultiply(x)
  45. }
  46. static valueOf() {
  47. if (typeof arguments[0] === 'string') {
  48. const str = arguments[0]
  49. return DD.parse(str)
  50. } else if (typeof arguments[0] === 'number') {
  51. const x = arguments[0]
  52. return new DD(x)
  53. }
  54. }
  55. static sqrt(x) {
  56. return DD.valueOf(x).sqrt()
  57. }
  58. static parse(str) {
  59. let i = 0
  60. const strlen = str.length
  61. while (Character.isWhitespace(str.charAt(i))) i++
  62. let isNegative = false
  63. if (i < strlen) {
  64. const signCh = str.charAt(i)
  65. if (signCh === '-' || signCh === '+') {
  66. i++
  67. if (signCh === '-') isNegative = true
  68. }
  69. }
  70. const val = new DD()
  71. let numDigits = 0
  72. let numBeforeDec = 0
  73. let exp = 0
  74. let hasDecimalChar = false
  75. while (true) {
  76. if (i >= strlen) break
  77. const ch = str.charAt(i)
  78. i++
  79. if (Character.isDigit(ch)) {
  80. const d = ch - '0'
  81. val.selfMultiply(DD.TEN)
  82. val.selfAdd(d)
  83. numDigits++
  84. continue
  85. }
  86. if (ch === '.') {
  87. numBeforeDec = numDigits
  88. hasDecimalChar = true
  89. continue
  90. }
  91. if (ch === 'e' || ch === 'E') {
  92. const expStr = str.substring(i)
  93. try {
  94. exp = Integer.parseInt(expStr)
  95. } catch (ex) {
  96. if (ex instanceof NumberFormatException)
  97. throw new NumberFormatException('Invalid exponent ' + expStr + ' in string ' + str)
  98. else throw ex
  99. } finally {}
  100. break
  101. }
  102. throw new NumberFormatException('Unexpected character \'' + ch + '\' at position ' + i + ' in string ' + str)
  103. }
  104. let val2 = val
  105. if (!hasDecimalChar) numBeforeDec = numDigits
  106. const numDecPlaces = numDigits - numBeforeDec - exp
  107. if (numDecPlaces === 0) {
  108. val2 = val
  109. } else if (numDecPlaces > 0) {
  110. const scale = DD.TEN.pow(numDecPlaces)
  111. val2 = val.divide(scale)
  112. } else if (numDecPlaces < 0) {
  113. const scale = DD.TEN.pow(-numDecPlaces)
  114. val2 = val.multiply(scale)
  115. }
  116. if (isNegative)
  117. return val2.negate()
  118. return val2
  119. }
  120. static createNaN() {
  121. return new DD(Double.NaN, Double.NaN)
  122. }
  123. static copy(dd) {
  124. return new DD(dd)
  125. }
  126. static magnitude(x) {
  127. const xAbs = Math.abs(x)
  128. const xLog10 = Math.log(xAbs) / Math.log(10)
  129. let xMag = Math.trunc(Math.floor(xLog10))
  130. const xApprox = Math.pow(10, xMag)
  131. if (xApprox * 10 <= xAbs) xMag += 1
  132. return xMag
  133. }
  134. static stringOfChar(ch, len) {
  135. const buf = new StringBuffer()
  136. for (let i = 0; i < len; i++)
  137. buf.append(ch)
  138. return buf.toString()
  139. }
  140. le(y) {
  141. return this._hi < y._hi || this._hi === y._hi && this._lo <= y._lo
  142. }
  143. extractSignificantDigits(insertDecimalPoint, magnitude) {
  144. let y = this.abs()
  145. let mag = DD.magnitude(y._hi)
  146. const scale = DD.TEN.pow(mag)
  147. y = y.divide(scale)
  148. if (y.gt(DD.TEN)) {
  149. y = y.divide(DD.TEN)
  150. mag += 1
  151. } else if (y.lt(DD.ONE)) {
  152. y = y.multiply(DD.TEN)
  153. mag -= 1
  154. }
  155. const decimalPointPos = mag + 1
  156. const buf = new StringBuffer()
  157. const numDigits = DD.MAX_PRINT_DIGITS - 1
  158. for (let i = 0; i <= numDigits; i++) {
  159. if (insertDecimalPoint && i === decimalPointPos)
  160. buf.append('.')
  161. const digit = Math.trunc(y._hi)
  162. if (digit < 0 || digit > 9) {}
  163. if (digit < 0)
  164. break
  165. let rebiasBy10 = false
  166. let digitChar = 0
  167. if (digit > 9) {
  168. rebiasBy10 = true
  169. digitChar = '9'
  170. } else {
  171. digitChar = '0' + digit
  172. }
  173. buf.append(digitChar)
  174. y = y.subtract(DD.valueOf(digit)).multiply(DD.TEN)
  175. if (rebiasBy10) y.selfAdd(DD.TEN)
  176. let continueExtractingDigits = true
  177. const remMag = DD.magnitude(y._hi)
  178. if (remMag < 0 && Math.abs(remMag) >= numDigits - i) continueExtractingDigits = false
  179. if (!continueExtractingDigits) break
  180. }
  181. magnitude[0] = mag
  182. return buf.toString()
  183. }
  184. sqr() {
  185. return this.multiply(this)
  186. }
  187. doubleValue() {
  188. return this._hi + this._lo
  189. }
  190. subtract() {
  191. if (arguments[0] instanceof DD) {
  192. const y = arguments[0]
  193. return this.add(y.negate())
  194. } else if (typeof arguments[0] === 'number') {
  195. const y = arguments[0]
  196. return this.add(-y)
  197. }
  198. }
  199. equals() {
  200. if (arguments.length === 1 && arguments[0] instanceof DD) {
  201. const y = arguments[0]
  202. return this._hi === y._hi && this._lo === y._lo
  203. }
  204. }
  205. isZero() {
  206. return this._hi === 0.0 && this._lo === 0.0
  207. }
  208. selfSubtract() {
  209. if (arguments[0] instanceof DD) {
  210. const y = arguments[0]
  211. if (this.isNaN()) return this
  212. return this.selfAdd(-y._hi, -y._lo)
  213. } else if (typeof arguments[0] === 'number') {
  214. const y = arguments[0]
  215. if (this.isNaN()) return this
  216. return this.selfAdd(-y, 0.0)
  217. }
  218. }
  219. getSpecialNumberString() {
  220. if (this.isZero()) return '0.0'
  221. if (this.isNaN()) return 'NaN '
  222. return null
  223. }
  224. min(x) {
  225. if (this.le(x))
  226. return this
  227. else
  228. return x
  229. }
  230. selfDivide() {
  231. if (arguments.length === 1) {
  232. if (arguments[0] instanceof DD) {
  233. const y = arguments[0]
  234. return this.selfDivide(y._hi, y._lo)
  235. } else if (typeof arguments[0] === 'number') {
  236. const y = arguments[0]
  237. return this.selfDivide(y, 0.0)
  238. }
  239. } else if (arguments.length === 2) {
  240. const yhi = arguments[0], ylo = arguments[1]
  241. let hc = null, tc = null, hy = null, ty = null, C = null, c = null, U = null, u = null
  242. C = this._hi / yhi
  243. c = DD.SPLIT * C
  244. hc = c - C
  245. u = DD.SPLIT * yhi
  246. hc = c - hc
  247. tc = C - hc
  248. hy = u - yhi
  249. U = C * yhi
  250. hy = u - hy
  251. ty = yhi - hy
  252. u = hc * hy - U + hc * ty + tc * hy + tc * ty
  253. c = (this._hi - U - u + this._lo - C * ylo) / yhi
  254. u = C + c
  255. this._hi = u
  256. this._lo = C - u + c
  257. return this
  258. }
  259. }
  260. dump() {
  261. return 'DD<' + this._hi + ', ' + this._lo + '>'
  262. }
  263. divide() {
  264. if (arguments[0] instanceof DD) {
  265. const y = arguments[0]
  266. let hc = null, tc = null, hy = null, ty = null, C = null, c = null, U = null, u = null
  267. C = this._hi / y._hi
  268. c = DD.SPLIT * C
  269. hc = c - C
  270. u = DD.SPLIT * y._hi
  271. hc = c - hc
  272. tc = C - hc
  273. hy = u - y._hi
  274. U = C * y._hi
  275. hy = u - hy
  276. ty = y._hi - hy
  277. u = hc * hy - U + hc * ty + tc * hy + tc * ty
  278. c = (this._hi - U - u + this._lo - C * y._lo) / y._hi
  279. u = C + c
  280. const zhi = u
  281. const zlo = C - u + c
  282. return new DD(zhi, zlo)
  283. } else if (typeof arguments[0] === 'number') {
  284. const y = arguments[0]
  285. if (Double.isNaN(y)) return DD.createNaN()
  286. return DD.copy(this).selfDivide(y, 0.0)
  287. }
  288. }
  289. ge(y) {
  290. return this._hi > y._hi || this._hi === y._hi && this._lo >= y._lo
  291. }
  292. pow(exp) {
  293. if (exp === 0.0) return DD.valueOf(1.0)
  294. let r = new DD(this)
  295. let s = DD.valueOf(1.0)
  296. let n = Math.abs(exp)
  297. if (n > 1)
  298. while (n > 0) {
  299. if (n % 2 === 1)
  300. s.selfMultiply(r)
  301. n /= 2
  302. if (n > 0) r = r.sqr()
  303. }
  304. else
  305. s = r
  306. if (exp < 0) return s.reciprocal()
  307. return s
  308. }
  309. ceil() {
  310. if (this.isNaN()) return DD.NaN
  311. const fhi = Math.ceil(this._hi)
  312. let flo = 0.0
  313. if (fhi === this._hi)
  314. flo = Math.ceil(this._lo)
  315. return new DD(fhi, flo)
  316. }
  317. compareTo(o) {
  318. const other = o
  319. if (this._hi < other._hi) return -1
  320. if (this._hi > other._hi) return 1
  321. if (this._lo < other._lo) return -1
  322. if (this._lo > other._lo) return 1
  323. return 0
  324. }
  325. rint() {
  326. if (this.isNaN()) return this
  327. const plus5 = this.add(0.5)
  328. return plus5.floor()
  329. }
  330. setValue() {
  331. if (arguments[0] instanceof DD) {
  332. const value = arguments[0]
  333. this.init(value)
  334. return this
  335. } else if (typeof arguments[0] === 'number') {
  336. const value = arguments[0]
  337. this.init(value)
  338. return this
  339. }
  340. }
  341. max(x) {
  342. if (this.ge(x))
  343. return this
  344. else
  345. return x
  346. }
  347. sqrt() {
  348. if (this.isZero()) return DD.valueOf(0.0)
  349. if (this.isNegative())
  350. return DD.NaN
  351. const x = 1.0 / Math.sqrt(this._hi)
  352. const ax = this._hi * x
  353. const axdd = DD.valueOf(ax)
  354. const diffSq = this.subtract(axdd.sqr())
  355. const d2 = diffSq._hi * (x * 0.5)
  356. return axdd.add(d2)
  357. }
  358. selfAdd() {
  359. if (arguments.length === 1) {
  360. if (arguments[0] instanceof DD) {
  361. const y = arguments[0]
  362. return this.selfAdd(y._hi, y._lo)
  363. } else if (typeof arguments[0] === 'number') {
  364. const y = arguments[0]
  365. let H = null, h = null, S = null, s = null, e = null, f = null
  366. S = this._hi + y
  367. e = S - this._hi
  368. s = S - e
  369. s = y - e + (this._hi - s)
  370. f = s + this._lo
  371. H = S + f
  372. h = f + (S - H)
  373. this._hi = H + h
  374. this._lo = h + (H - this._hi)
  375. return this
  376. }
  377. } else if (arguments.length === 2) {
  378. const yhi = arguments[0], ylo = arguments[1]
  379. let H = null, h = null, T = null, t = null, S = null, s = null, e = null, f = null
  380. S = this._hi + yhi
  381. T = this._lo + ylo
  382. e = S - this._hi
  383. f = T - this._lo
  384. s = S - e
  385. t = T - f
  386. s = yhi - e + (this._hi - s)
  387. t = ylo - f + (this._lo - t)
  388. e = s + T
  389. H = S + e
  390. h = e + (S - H)
  391. e = t + h
  392. const zhi = H + e
  393. const zlo = e + (H - zhi)
  394. this._hi = zhi
  395. this._lo = zlo
  396. return this
  397. }
  398. }
  399. selfMultiply() {
  400. if (arguments.length === 1) {
  401. if (arguments[0] instanceof DD) {
  402. const y = arguments[0]
  403. return this.selfMultiply(y._hi, y._lo)
  404. } else if (typeof arguments[0] === 'number') {
  405. const y = arguments[0]
  406. return this.selfMultiply(y, 0.0)
  407. }
  408. } else if (arguments.length === 2) {
  409. const yhi = arguments[0], ylo = arguments[1]
  410. let hx = null, tx = null, hy = null, ty = null, C = null, c = null
  411. C = DD.SPLIT * this._hi
  412. hx = C - this._hi
  413. c = DD.SPLIT * yhi
  414. hx = C - hx
  415. tx = this._hi - hx
  416. hy = c - yhi
  417. C = this._hi * yhi
  418. hy = c - hy
  419. ty = yhi - hy
  420. c = hx * hy - C + hx * ty + tx * hy + tx * ty + (this._hi * ylo + this._lo * yhi)
  421. const zhi = C + c
  422. hx = C - zhi
  423. const zlo = c + hx
  424. this._hi = zhi
  425. this._lo = zlo
  426. return this
  427. }
  428. }
  429. selfSqr() {
  430. return this.selfMultiply(this)
  431. }
  432. floor() {
  433. if (this.isNaN()) return DD.NaN
  434. const fhi = Math.floor(this._hi)
  435. let flo = 0.0
  436. if (fhi === this._hi)
  437. flo = Math.floor(this._lo)
  438. return new DD(fhi, flo)
  439. }
  440. negate() {
  441. if (this.isNaN()) return this
  442. return new DD(-this._hi, -this._lo)
  443. }
  444. clone() {
  445. try {
  446. return null
  447. } catch (ex) {
  448. if (ex instanceof CloneNotSupportedException)
  449. return null
  450. else throw ex
  451. } finally {}
  452. }
  453. multiply() {
  454. if (arguments[0] instanceof DD) {
  455. const y = arguments[0]
  456. if (y.isNaN()) return DD.createNaN()
  457. return DD.copy(this).selfMultiply(y)
  458. } else if (typeof arguments[0] === 'number') {
  459. const y = arguments[0]
  460. if (Double.isNaN(y)) return DD.createNaN()
  461. return DD.copy(this).selfMultiply(y, 0.0)
  462. }
  463. }
  464. isNaN() {
  465. return Double.isNaN(this._hi)
  466. }
  467. intValue() {
  468. return Math.trunc(this._hi)
  469. }
  470. toString() {
  471. const mag = DD.magnitude(this._hi)
  472. if (mag >= -3 && mag <= 20) return this.toStandardNotation()
  473. return this.toSciNotation()
  474. }
  475. toStandardNotation() {
  476. const specialStr = this.getSpecialNumberString()
  477. if (specialStr !== null) return specialStr
  478. const magnitude = new Array(1).fill(null)
  479. const sigDigits = this.extractSignificantDigits(true, magnitude)
  480. const decimalPointPos = magnitude[0] + 1
  481. let num = sigDigits
  482. if (sigDigits.charAt(0) === '.') {
  483. num = '0' + sigDigits
  484. } else if (decimalPointPos < 0) {
  485. num = '0.' + DD.stringOfChar('0', -decimalPointPos) + sigDigits
  486. } else if (sigDigits.indexOf('.') === -1) {
  487. const numZeroes = decimalPointPos - sigDigits.length
  488. const zeroes = DD.stringOfChar('0', numZeroes)
  489. num = sigDigits + zeroes + '.0'
  490. }
  491. if (this.isNegative()) return '-' + num
  492. return num
  493. }
  494. reciprocal() {
  495. let hc = null, tc = null, hy = null, ty = null, C = null, c = null, U = null, u = null
  496. C = 1.0 / this._hi
  497. c = DD.SPLIT * C
  498. hc = c - C
  499. u = DD.SPLIT * this._hi
  500. hc = c - hc
  501. tc = C - hc
  502. hy = u - this._hi
  503. U = C * this._hi
  504. hy = u - hy
  505. ty = this._hi - hy
  506. u = hc * hy - U + hc * ty + tc * hy + tc * ty
  507. c = (1.0 - U - u - C * this._lo) / this._hi
  508. const zhi = C + c
  509. const zlo = C - zhi + c
  510. return new DD(zhi, zlo)
  511. }
  512. toSciNotation() {
  513. if (this.isZero()) return DD.SCI_NOT_ZERO
  514. const specialStr = this.getSpecialNumberString()
  515. if (specialStr !== null) return specialStr
  516. const magnitude = new Array(1).fill(null)
  517. const digits = this.extractSignificantDigits(false, magnitude)
  518. const expStr = DD.SCI_NOT_EXPONENT_CHAR + magnitude[0]
  519. if (digits.charAt(0) === '0')
  520. throw new IllegalStateException('Found leading zero: ' + digits)
  521. let trailingDigits = ''
  522. if (digits.length > 1) trailingDigits = digits.substring(1)
  523. const digitsWithDecimal = digits.charAt(0) + '.' + trailingDigits
  524. if (this.isNegative()) return '-' + digitsWithDecimal + expStr
  525. return digitsWithDecimal + expStr
  526. }
  527. abs() {
  528. if (this.isNaN()) return DD.NaN
  529. if (this.isNegative()) return this.negate()
  530. return new DD(this)
  531. }
  532. isPositive() {
  533. return this._hi > 0.0 || this._hi === 0.0 && this._lo > 0.0
  534. }
  535. lt(y) {
  536. return this._hi < y._hi || this._hi === y._hi && this._lo < y._lo
  537. }
  538. add() {
  539. if (arguments[0] instanceof DD) {
  540. const y = arguments[0]
  541. return DD.copy(this).selfAdd(y)
  542. } else if (typeof arguments[0] === 'number') {
  543. const y = arguments[0]
  544. return DD.copy(this).selfAdd(y)
  545. }
  546. }
  547. init() {
  548. if (arguments.length === 1) {
  549. if (typeof arguments[0] === 'number') {
  550. const x = arguments[0]
  551. this._hi = x
  552. this._lo = 0.0
  553. } else if (arguments[0] instanceof DD) {
  554. const dd = arguments[0]
  555. this._hi = dd._hi
  556. this._lo = dd._lo
  557. }
  558. } else if (arguments.length === 2) {
  559. const hi = arguments[0], lo = arguments[1]
  560. this._hi = hi
  561. this._lo = lo
  562. }
  563. }
  564. gt(y) {
  565. return this._hi > y._hi || this._hi === y._hi && this._lo > y._lo
  566. }
  567. isNegative() {
  568. return this._hi < 0.0 || this._hi === 0.0 && this._lo < 0.0
  569. }
  570. trunc() {
  571. if (this.isNaN()) return DD.NaN
  572. if (this.isPositive()) return this.floor(); else return this.ceil()
  573. }
  574. signum() {
  575. if (this._hi > 0) return 1
  576. if (this._hi < 0) return -1
  577. if (this._lo > 0) return 1
  578. if (this._lo < 0) return -1
  579. return 0
  580. }
  581. get interfaces_() {
  582. return [Serializable, Comparable, Cloneable]
  583. }
  584. }
  585. DD.PI = new DD(3.141592653589793116e+00, 1.224646799147353207e-16)
  586. DD.TWO_PI = new DD(6.283185307179586232e+00, 2.449293598294706414e-16)
  587. DD.PI_2 = new DD(1.570796326794896558e+00, 6.123233995736766036e-17)
  588. DD.E = new DD(2.718281828459045091e+00, 1.445646891729250158e-16)
  589. DD.NaN = new DD(Double.NaN, Double.NaN)
  590. DD.EPS = 1.23259516440783e-32
  591. DD.SPLIT = 134217729.0
  592. DD.MAX_PRINT_DIGITS = 32
  593. DD.TEN = DD.valueOf(10.0)
  594. DD.ONE = DD.valueOf(1.0)
  595. DD.SCI_NOT_EXPONENT_CHAR = 'E'
  596. DD.SCI_NOT_ZERO = '0.0E0'