1234abcecba4321

notations

Mar 28th, 2019
88
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.08 KB | None | 0 0
  1. [28/03/2019]
  2. Roman
  3. this._decimalValue = [ 1000000, 900000, 500000, 400000, 100000, 90000, 50000, 40000, 10000, 9000, 5000, 4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ];
  4. this._romanNumeral = [ "M̄", "C̄M̄", "D̄", "C̄D̄", "C̄", "X̄C̄", "L̄", "X̄L̄", "X̄", "ⅯX̄", "V̄", "ⅯV̄", "Ⅿ", "ⅭⅯ", "Ⅾ", "ⅭⅮ", "Ⅽ", "ⅩⅭ", "Ⅼ", "ⅩⅬ", "Ⅹ", "ⅠⅩ","Ⅴ", "ⅠⅤ", "Ⅰ" ];
  5. this._romanFractions = ["", "·", ":", "∴", "∷", "⁙"];
  6. this.maximum = 4000000;
  7. this._maxLog10 = Math.log10(this.maximum);
  8.  
  9. formatDecimal(value, places) {
  10. if (value.lt(this.maximum)) {
  11. return this.romanize(value.toNumber());
  12. }
  13. const log10 = value.log10();
  14. const maximums = log10 / this._maxLog10;
  15. const current = Math.pow(this.maximum, maximums - Math.floor(maximums));
  16. return `${this.romanize(current)}↑${this.formatDecimal(maximums.toDecimal())}`;
  17.  
  18. romanize(value) {
  19. const decimalValue = this._decimalValue;
  20. const romanNumeral = this._romanNumeral;
  21. const romanFractions = this._romanFractions;
  22. let roman = String.empty;
  23. for (let i = 0; i < decimalValue.length; i++) {
  24. while (decimalValue[i] <= value) {
  25. roman += romanNumeral[i];
  26. value -= decimalValue[i];
  27. }
  28. }
  29. let duodecimal = Math.round(Math.floor(value * 10) * 1.2);
  30. if (duodecimal === 0) {
  31. return roman === String.empty ? "nulla" : roman;
  32. }
  33. if (duodecimal > 5) {
  34. duodecimal -= 6;
  35. roman += "S";
  36. }
  37. roman += romanFractions[duodecimal];
  38. return roman;
  39. }
  40.  
  41. formatDecimal (places does nothing)
  42. if (value<4e6) romanize(n)
  43. else romanize(4e6 ^ log4000000(n)%1) + ↑ + formatDecimal(log4000000(n))
  44.  
  45. this._decimalValue = [ 1000000, 900000, 500000, 400000, 100000, 90000, 50000, 40000, 10000, 9000, 5000, 4000, 1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1 ];
  46. this._romanNumeral = [ "M̄", "C̄M̄", "D̄", "C̄D̄", "C̄", "X̄C̄", "L̄", "X̄L̄", "X̄", "ⅯX̄", "V̄", "ⅯV̄", "Ⅿ", "ⅭⅯ", "Ⅾ", "ⅭⅮ", "Ⅽ", "ⅩⅭ", "Ⅼ", "ⅩⅬ", "Ⅹ", "ⅠⅩ","Ⅴ", "ⅠⅤ", "Ⅰ" ];
  47. this._romanFractions = ["", "·", ":", "∴", "∷", "⁙"];
  48. romanize(value)
  49. for each value in decimalValue in order: while value >= decimalValue[i], append the roman value to string and subtract decimalValue[i] from value.
  50. duodecimal = round(floor(value*10)*1.2) //that *10 should be %10 obviously
  51. if(duodecimal==0) end; if roman is empty (value = 0) return "nulla", otherwise return the string.
  52. if(duodecimal>5) add "S", subtract 6
  53. append the fraction value (romanFractions[duodecimal]) to end
  54.  
  55. dots:
  56. formatUnder1000(value, places) {
  57. return this.dotify(value * 254);
  58. }
  59.  
  60. formatInfinite() {
  61. return "⣿⠀⣿";
  62. }
  63.  
  64. formatDecimal(value, places) {
  65. if (value.lt(16387063.9980315)) {
  66. return this.dotify(value.toNumber() * 254);
  67. }
  68. const log = value.log(254);
  69. const exponent = Math.floor(log - 2);
  70. const mantissa = Math.pow(254, log - exponent);
  71. return this.dotify(exponent) + "⣿" + this.dotify(mantissa * 254);
  72. }
  73.  
  74. dotify(value, pad) {
  75. const DOT_DIGITS =
  76. "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿" +
  77. "⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿" +
  78. "⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿" +
  79. "⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
  80.  
  81. value = Math.round(value);
  82. if (!pad && value < 254) return DOT_DIGITS[value + 1];
  83. if (value < 64516) return DOT_DIGITS[Math.floor(value / 254) + 1] + DOT_DIGITS[value % 254 + 1];
  84. return this.dotify(Math.floor(value / 64516)) + this.dotify(value % 64516, true);
  85. }
  86.  
  87. formatDecimal
  88. if (value < 16387063.9980315) dotify(value*254)
  89. log = log254(value)
  90. exponent = floor(log-2)
  91. dotify(exponent) + ⣿ + dotify(254^(log-exponent+1))
  92.  
  93. dotify(value,pad) {pad skips the <254 step}
  94. "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿" +
  95. "⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷⡸⡹⡺⡻⡼⡽⡾⡿" +
  96. "⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿" +
  97. "⣀⣁⣂⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿";
  98. value = round(value)
  99. if (value < 254) return DOT_DIGITS[value + 1]; (one digit base254 number)
  100. if (value < 64516) return DOT_DIGITS[floor(value/254)+1] + DOT_DIGITS[value%254+1]; (two digit base254 number)
  101. return dotify(floor(value/64516)) + dotify(value%64516,true); (four digit base254 number)
  102.  
  103. zalgo:
  104. constructor() {
  105. super("Zalgo");
  106. this._zalgoChars = ['\u030D', '\u0336', '\u0353', '\u033F', '\u0489', '\u0330', '\u031A', '\u0338', '\u035A', '\u0337'];
  107. this._heComes = ["H", "E" , " ", "C" , "O" , "M" , "E", "S"];
  108. }
  109.  
  110. get isPainful() {
  111. return true;
  112. }
  113.  
  114. formatInfinite() {
  115. return this._heComes
  116. .map(char => char + this._zalgoChars.randomElement())
  117. .join("");
  118. }
  119.  
  120. formatUnder1000(value, places) {
  121. return this.heComes(value.toDecimal());
  122. }
  123.  
  124. formatDecimal(value, places) {
  125. return this.heComes(value);
  126. }
  127.  
  128. /**
  129. * @param {Decimal} value
  130. * @return {string}
  131. */
  132. heComes(value) {
  133. // Eternity seems to happen around e66666 antimatter, who would've thought? Scaled down to 1000.
  134. let scaled = value.clampMin(1).log10() / 66666 * 1000;
  135. let displayPart = scaled.toFixed(2);
  136. let zalgoPart = Math.floor(Math.abs(Math.pow(2, 30) * (scaled - displayPart)));
  137.  
  138. let displayChars = Array.from(formatWithCommas(displayPart));
  139. let zalgoIndices = Array.from(zalgoPart.toString() + scaled.toFixed(0));
  140.  
  141. for (let i = 0; i < zalgoIndices.length; i++) {
  142. let zalgoIndex = parseInt(zalgoIndices[i]);
  143. let displayIndex = 7 * i % displayChars.length;
  144. displayChars[displayIndex] += this._zalgoChars[zalgoIndex];
  145. }
  146.  
  147. return displayChars.join("");
  148. }
  149.  
  150. formatInfinite: randomly zalgo each character in HE COMES.
  151. heComes(value)
  152. scaled ~= log10(value)/66.666
  153. displayPart = scaled, to 2 places
  154. zalgoPart = floor(abs(1073741824 * scaled-displayPart))
  155. hard to parse will do later
  156.  
  157. hex:
  158. formatInfinite() {
  159. return "FFFFFFFF";
  160. }
  161.  
  162. formatDecimal(value) {
  163. // The `this.rawValue(x, 32, 8)` returns an integer between 0 and 2^32,
  164. // the .toString(16).toUpperCase().padStart(8, '0') formats it as
  165. // 8 hexadecimal digits.
  166. return this.rawValue(value, 32, 8).toString(16).toUpperCase().padStart(8, '0');
  167. }
  168.  
  169. modifiedLogarithm(x) {
  170. // This function implements a tweak to the usual logarithm.
  171. // It has the same value at powers of 2 but is linear between
  172. // powers of 2 (so for example, f(3) = 1.5).
  173. const floorOfLog = Math.floor(Decimal.log2(x));
  174. const previousPowerOfTwo = Decimal.pow(2, floorOfLog);
  175. const fractionToNextPowerOfTwo = Decimal.div(x, previousPowerOfTwo).toNumber() - 1;
  176. return floorOfLog + fractionToNextPowerOfTwo;
  177. }
  178.  
  179. rawValue(value, numberOfBits, extraPrecisionForRounding) {
  180. return this.getValueFromSigns(this.getSigns(value, numberOfBits, extraPrecisionForRounding), numberOfBits);
  181. }
  182.  
  183. isFinite(x) {
  184. if (typeof x === "number") {
  185. return isFinite(x);
  186. }
  187. return isFinite(x.e) && isFinite(x.mantissa);
  188. }
  189.  
  190. getSigns(value, numberOfBits, extraPrecisionForRounding) {
  191. // Extra precision is an arbitrary number, it only controls rounding of
  192. // the last digit, if it's 0 the last digit will almost always be odd
  193. // for non-dyadic x, if it's too high the code might be slower.
  194. // 8 (the value used) should be high enough for good results.
  195. let signs = [];
  196. for (let i = 0; i < numberOfBits + extraPrecisionForRounding; i++) {
  197. if (!this.isFinite(value)) {
  198. break;
  199. }
  200. if (Decimal.lt(value, 0)) {
  201. signs.push(this.signs.NEGATIVE);
  202. value = Decimal.times(value, -1);
  203. } else {
  204. signs.push(this.signs.POSITIVE);
  205. }
  206. value = this.modifiedLogarithm(value);
  207. }
  208. return signs;
  209. }
  210.  
  211. getValueFromSigns(signs, numberOfBits) {
  212. // We need to use 0 as the initial value for result,
  213. // rather than, for example, 0.5. This is so that the sign list of 0
  214. // (passed in here as signs), which is just [Notation.hex.signs.POSITIVE],
  215. // becomes 1 / 2 + 0 = 0.5.
  216. // Another way of thinking about this:
  217. // The general way getSigns terminates, when it starts with a finite number,
  218. // is by taking the log of 0, which is -Infinity, which is the lowest number,
  219. // and which is also not finite, leading to the getSigns loop breaking. If you pass
  220. // -Infinity into getSigns, the result will be an empty list, so we want this function
  221. // to turn an empty list into 0. So the initial value has to be 0.
  222. // If you pass Infinity into getSigns, the result will also be an empty list,
  223. // but modifiedLogarithm never returns Infinity so the only way value can be Infinity
  224. // in getSigns is if Infinity was initially passed in, which should never happen.
  225. let result = 0;
  226. for (let i = signs.length - 1; i >= 0; i--) {
  227. if (signs[i] === this.signs.NEGATIVE) {
  228. result = 1 / 2 - result / 2;
  229. } else {
  230. result = 1 / 2 + result / 2;
  231. }
  232. }
  233. return Math.round(result * Math.pow(2, numberOfBits));
  234. }
  235.  
  236. formatDecimal:
  237. signs = []
  238. for (i<40) {
  239. if (value isn't finite) break //log(0) = -infinity
  240. if(value<0) value *= -1; sign += negative //this is evil... it can only affect the last bit
  241. else signs += positive
  242. floor = floor(log2(x))
  243. value = floor+ x/(2^floor) -1
  244. }
  245.  
  246. result = 0 //feels arbitrary but ok
  247. for (i:signs in reverse order) {
  248. if (i = negative) result = 0.5 - result/2
  249. else result = 0.5 + result/2
  250. }
  251. return round(result*2^32).toString(16).toUpperCase().padStart(8, '0');
  252.  
  253. imperial:
  254. // The first column is the size in pL
  255. // the second is the name
  256. // the third is an index offset (going backwards) to the smallest unit that
  257. // is larger than "roudning error" for the unit in question (so, for a tun,
  258. // this is 7, which means that if we're within one pin of a tun, we'll say we're
  259. // "almost a tun" rather than "a pin short of a tun"
  260. this.VOLUME_UNITS = [
  261. [0, "pL", 0],
  262. [61611520, "minim", 0],
  263. [61611520*60, "dram", 1],
  264. [61611520*60*8, "ounce", 2],
  265. [61611520*60*8*4, "gill", 2],
  266. [61611520*60*8*4*2, "cup", 3],
  267. [61611520*60*8*4*2*2, "pint", 4],
  268. [61611520*60*8*4*2*2*2, "quart", 4],
  269. [61611520*60*8*4*2*2*2*4, "gallon", 4],
  270. [61611520*60*8*4*2*2*2*4*4.5, "pin", 3],
  271. [61611520*60*8*4*2*2*2*4*9, "firkin", 3],
  272. [61611520*60*8*4*2*2*2*4*18, "kilderkin", 4],
  273. [61611520*60*8*4*2*2*2*4*36, "barrel", 4],
  274. [61611520*60*8*4*2*2*2*4*54, "hogshead", 5],
  275. [61611520*60*8*4*2*2*2*4*72, "puncheon", 6],
  276. [61611520*60*8*4*2*2*2*4*108, "butt", 7],
  277. [61611520*60*8*4*2*2*2*4*216, "tun", 7],
  278. ];
  279. this.MINIMS = this.VOLUME_UNITS[1];
  280. this.VOLUME_ADJECTIVES = ["minute ", "tiny ", "petite ", "small ", "modest ", "medium ", "generous ",
  281. "large ", "great ", "huge ", "gigantic ", "colossal ", "vast ", "cosmic "];
  282. this.VOWELS = new Set("aeiouAEIOU");
  283. this.maxVolume = 10 * this.VOLUME_UNITS[this.VOLUME_UNITS.length-1][0];
  284. this.logMaxVolume = Math.log10(this.maxVolume);
  285. this.reduceRatio = Math.log10(this.maxVolume/this.MINIMS[0]);
  286. }
  287.  
  288. get isPainful() {
  289. return true;
  290. }
  291.  
  292. formatUnder1000(value) {
  293. return this.formatDecimal(new Decimal(value));
  294. }
  295.  
  296. formatDecimal(value) {
  297. if (value.lt(this.maxVolume)) {
  298. return this.convertToVolume(value.toNumber(), this.VOLUME_ADJECTIVES[0]);
  299. }
  300. let logValue = value.log10() - this.logMaxVolume;
  301. let adjectiveIndex = 1;
  302. while (logValue > this.reduceRatio) {
  303. adjectiveIndex++;
  304. logValue /= this.reduceRatio;
  305. }
  306. return this.convertToVolume(Math.pow(10, logValue) * this.MINIMS[0], this.VOLUME_ADJECTIVES[adjectiveIndex]);
  307. }
  308.  
  309. convertToVolume(x, adjective) {
  310. const volIdx = this.findVolumeUnit(x);
  311. if (volIdx === 0) return this.formatMetric(x);
  312.  
  313. const smallStr = this.checkSmallUnits(adjective, x, volIdx);
  314. if (smallStr) return smallStr;
  315.  
  316. const big = this.VOLUME_UNITS[volIdx]
  317. const numBig = Math.floor(x / big[0]);
  318. const remainder = x - numBig * big[0];
  319. // When we are within a specified rounding error, unit break:
  320. if (volIdx < this.VOLUME_UNITS.length - 1) {
  321. const ret = this.checkAlmost(adjective, x, 0, volIdx + 1);
  322. if (ret) return ret;
  323. }
  324. const nearMultiple = this.checkAlmost(adjective, remainder, numBig, volIdx);
  325. if (nearMultiple) return nearMultiple;
  326. // just over a multiple, in units that are too small:
  327. if (remainder < this.VOLUME_UNITS[volIdx - big[2]][0]) {
  328. return this.pluralOrArticle(numBig, adjective + big[1]);
  329. }
  330. // Search for the best unit to pair with:
  331. let numBest = Math.floor(remainder / this.VOLUME_UNITS[volIdx - 1][0]);
  332. let bestUnitIndex = volIdx - 1;
  333. let bestUnitError = remainder - numBest * this.VOLUME_UNITS[volIdx - 1][0];
  334. for (let thirdUnitIndex = volIdx - 2; thirdUnitIndex > 0 && thirdUnitIndex > volIdx - big[2]; --thirdUnitIndex) {
  335. const third = this.VOLUME_UNITS[thirdUnitIndex];
  336. const numThird = Math.floor(remainder / third[0]);
  337. // If we have a lot of the unit under consideration -- then stop. The exception is in
  338. // case of minims, where it may be normal to have a bunch of them; in that case, we print
  339. // drams if possible.
  340. if (numThird > 9 && (thirdUnitIndex != 1 || bestUnits)) break;
  341. // we are using floor, so we can compare error diretly, without abs
  342. const thirdUnitError = remainder - numThird * third[0];
  343. if (thirdUnitError < 0.99 * bestUnitError) {
  344. numBest = numThird;
  345. bestUnitIndex = thirdUnitIndex;
  346. bestUnitError = thirdUnitError;
  347. }
  348. }
  349. return this.bigAndSmall(adjective, numBig, big, numBest, this.VOLUME_UNITS[bestUnitIndex]);
  350. }
  351.  
  352. /**
  353. * Format a small quantity that is less than the smallest minim; this is done without adjective
  354. * @param {number} x
  355. **/
  356. formatMetric(x) {
  357. // The jump from metric to minim is sudden. Small values (< 10) get more decimal places
  358. // because that's usually something like sacrifice multiplier
  359. if (x < 1000) {
  360. return ((x < 10 || x === Math.round(x)) ? x.toFixed(2) : x.toFixed(0)) + "pL"
  361. }
  362. if (x < 1e6) return (x / 1000).toPrecision(4) + "nL";
  363. return (x / 1e6).toPrecision(4) + "μL";
  364. }
  365.  
  366. /**
  367. * handles cases involving everything up to ounces; in the case of ounces it may
  368. * return nothing, in which case, the normal code path should be used.
  369. * @param {string} adjective will be attached to unit
  370. * @param {number} x value to be formatted
  371. * @param {number} volIdx index into VOLUME_UNITS for x (largest unit smaller than x)
  372. * @returns {string?} the formatted output, if within the capabilities of this function
  373. */
  374. checkSmallUnits(adjective, x, volIdx) {
  375. const big = this.VOLUME_UNITS[volIdx];
  376. // Check for some minims short of a small unit break:
  377. if (volIdx <= 3 && x + 9.5 * this.MINIMS[0] > this.VOLUME_UNITS[volIdx + 1][0]) {
  378. return this.almostOrShortOf(x, adjective, 1, this.VOLUME_UNITS[volIdx + 1], this.MINIMS);
  379. }
  380. // minims to drams. This goes:
  381. // a minim
  382. // 1.5 minims <-- we don't do this with larger units
  383. // 10 minims ... 50 minims
  384. // 9 minims short of a dram
  385. // a minim short of a dram
  386. // almost a dram <-- handled above
  387. if (volIdx === 1) {
  388. const deciMinims = Math.round(x * 10 / big[0]);
  389. if (deciMinims === 10) return this.addArticle(adjective + big[1]);
  390. const places = deciMinims < 100 ? 1 : 0;
  391. return `${(deciMinims / 10).toFixed(places)} ${adjective}${big[1]}s`
  392. }
  393. if (volIdx === 2) {
  394. const numBig = Math.floor(x / big[0]);
  395. const remainder = x - numBig * big[0];
  396. if (remainder > 50.5 * this.MINIMS[0]) { // 9 minims short of a dram
  397. return this.almostOrShortOf(x, adjective, numBig + 1, big, this.MINIMS);
  398. }
  399. // for example, a dram and 15 minims
  400. const numSmall = Math.round(remainder / this.MINIMS[0]);
  401. return this.bigAndSmall(adjective, numBig, big, numSmall, this.MINIMS);
  402. }
  403. return null;
  404. }
  405.  
  406. /**
  407. * Search for the largest unit smaller than x
  408. * @param {number} x
  409. * @returns {number} index into VOLUME_UNITS
  410. **/
  411. findVolumeUnit(x) {
  412. let low = 0;
  413. let high = this.VOLUME_UNITS.length;
  414. let guess;
  415. while (high - low > 1) {
  416. guess = Math.floor((low + high) / 2);
  417. if (this.VOLUME_UNITS[guess][0] > x) high = guess;
  418. else low = guess;
  419. }
  420. return low;
  421. }
  422.  
  423. // Try to do "almost a big thing" or "a thing short of a big thing", based on the setting
  424. // we have for rounding error units; may return nothing if we are not actually near something
  425. checkAlmost(adjective, x, numBig, bigIndex) {
  426. const big = this.VOLUME_UNITS[bigIndex];
  427. if (x + this.VOLUME_UNITS[bigIndex - big[2]][0] >= big[0]) {
  428. return this.almost(adjective, numBig + 1, big);
  429. }
  430. const small = this.VOLUME_UNITS[bigIndex + 1 - big[2]];
  431. if (x + small[0] >= big[0]) {
  432. return this.shortOf(adjective, numBig + 1, big, 1, small);
  433. }
  434. return null;
  435. }
  436.  
  437. bigAndSmall(adjective, numBig, big, numSmall, small) {
  438. const bigStr = this.pluralOrArticle(numBig, adjective + big[1]);
  439. return numSmall === 0 ? bigStr : bigStr + " and " + this.pluralOrArticle(numSmall, small[1]);
  440. }
  441.  
  442. almost(adjective, numBig, big) {
  443. return "almost " + this.pluralOrArticle(numBig, adjective + big[1]);
  444. }
  445.  
  446. almostOrShortOf(x, adjective, numBig, big, small) {
  447. const short = Math.round((numBig * big[0] - x) / small[0]);
  448. return short
  449. ? this.shortOf(adjective, numBig, big, short, small)
  450. : this.almost(adjective, numBig, big);
  451. }
  452.  
  453. shortOf(adjective, numBig, big, numSmall, small) {
  454. return this.pluralOrArticle(numSmall, small[1]) + " short of " +
  455. this.pluralOrArticle(numBig, adjective + big[1]);
  456. }
  457.  
  458. pluralOrArticle(num, str) {
  459. return num === 1 ? this.addArticle(str) : num + " " + str + "s";
  460. }
  461.  
  462. addArticle(x) {
  463. return (this.VOWELS.has(x[0]) ? "an " : "a ") + x;
  464. }
  465.  
  466. MAX = 10*tun = 8176489463808000
  467. REDUCE = log10(MAX/minim) ~= 7.12290495817
  468. formatDecimal:
  469. if (value < MAX) convertToVolume(value,minute)
  470. logValue = log10(value) - log10(MAX)
  471. while (logValue > REDUCE) logValue /= REDUCE; adjective++
  472. convertToVolume(10^logValue)*minim, adjectiveIndex)
  473.  
  474. convertToVolume(x, adjective):
  475. volIdx = the highest adjective that is below x
  476. if (volIdx = 0) { //very small numbers below a minim
  477. if (x < 1000) {
  478. return ((x < 10 || x === Math.round(x)) ? x.toFixed(2) : x.toFixed(0)) + "pL" //tiny numbers have more precision because why not
  479. }
  480. if (x < 1e6) return (x / 1000).toPrecision(4) + "nL";
  481. return (x / 1e6).toPrecision(4) + "μL";
  482. }
  483.  
  484.  
  485. am tired will continue later
Add Comment
Please, Sign In to add comment