Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Utils.toFixed returns incorrect results in some cases #113

Closed
pixelzoom opened this issue Jun 22, 2022 · 34 comments
Closed

Utils.toFixed returns incorrect results in some cases #113

pixelzoom opened this issue Jun 22, 2022 · 34 comments

Comments

@pixelzoom
Copy link
Contributor

pixelzoom commented Jun 22, 2022

Discovered while working on phetsims/scenery-phet#747.

Utils.toFixed was created as a workaround for problems with built-in toFixed, which rounds differently on different browsers.

Here's the current implementation:

  /**
   * A predictable implementation of toFixed.
   * @public
   *
   * JavaScript's toFixed is notoriously buggy, behavior differs depending on browser,
   * because the spec doesn't specify whether to round or floor.
   * Rounding is symmetric for positive and negative values, see Utils.roundSymmetric.
   *
   * @param {number} value
   * @param {number} decimalPlaces
   * @returns {string}
   */
  toFixed( value, decimalPlaces ) {
    const multiplier = Math.pow( 10, decimalPlaces );
    const newValue = Utils.roundSymmetric( value * multiplier ) / multiplier;
    return newValue.toFixed( decimalPlaces ); // eslint-disable-line bad-sim-text
  },

But Utils.toFixed does not return the correct value in all cases. It's subject to floating-point error.

For example, this should be '35.86':

> phet.dot.Utils.toFixed( 35.855, 2 )
'35.85'

This is caused by value * multiplier in the implementation of Utils.toFixed:

> 35.855 * 100
3585.4999999999995

This problem could result in widespread errors in PhET sims. It's certainly affecting ScientificNotationNode.

Do we want to do anything about this? Can we do anything about this?

@pixelzoom
Copy link
Contributor Author

pixelzoom commented Jun 23, 2022

In the above commits, I added toFixedPointString.ts, with unit tests in toFixedPointStringTests.js. (I decided to put this function in its own file, since Util.js has not been converted to TypeScript.)

Function toFixedPointString has the same API as Number.toFixed and Util.toFixed, but performs no math operations. It does all of its work by manipulating strings. So it does not have the rounding and floating-point problems inherent in Number.toFixed and Utils.toFixed.

I'm planning to use this in ScientificNotationNode. And I'd like to discuss whether this should be a replacement for Utils.toFixed.

@zepumph
Copy link
Member

zepumph commented Jun 23, 2022

From dev meeting today, we will wait to discuss with @pixelzoom and @jonathanolson.

@pixelzoom pixelzoom changed the title Util.toFixed returns incorrect results in some cases Utils.toFixed returns incorrect results in some cases Jun 30, 2022
@jessegreenberg
Copy link
Contributor

jessegreenberg commented Jun 30, 2022

@liam-mulhall suggested a library like math.js that may have support for handling this.
@pixelzoom: Yes, we have discussed before. It could be a big change, we would have to use that any time we work with numbers. But it could be good to investigate.
@zepumph: Can we use a library in specific cases instead of using broadly?
@kathy-phet @pixelzoom @zepumph: Maybe we could use Math.js just in Utils.toFixed at first.

@pixelzoom: Since this is a systemic problem, should anything be done for ScientificNotationNode and build-a-nucleus?
@kathy-phet: That is not necessary, if we are going to address this it should be done generally.

@pixelzoom wrote a string manipulation algorithm to get around this in #113 (comment). But he found it couldn't be used for ScientificNotationNode because division was required before the string manipulation.
@zepumph: Can we change Utils.toFixed to use this?
@pixelzoom: Worried that it is not as performant as current implementation of Utils.toFixed.

@kathy-phet: Lets bring this up during quarterly goals discussion, this might be a good project to work on generally.

@zepumph
Copy link
Member

zepumph commented Jun 30, 2022

This investigation should be handled over in the epic issue in #116

@samreid
Copy link
Member

samreid commented Jul 5, 2022

This StackOverflow post refers to an MDN polyfill implementation they describe as "reliable rounding implementation". https://stackoverflow.com/questions/42109818/reliable-js-rounding-numbers-with-tofixed2-of-a-3-decimal-number.

I tested it in the browser console and it appeared to have the correct behavior for the error case above (same good behavior on Chrome and Firefox):

Math.round10(35.855, -2);
35.86

Note this returns a number instead of a string, so would still need one more step before it could be used for toFixed. I'm not sure if it addresses the case for ScientificNotationNode or not.

Also, we would want to adapt it to run as a regular function instead of monkey patching Math.

@pixelzoom
Copy link
Contributor Author

At 7/6/2022 quarterly-planning meeting, this was assigned to me for next steps, starting with the polyfill that @samreid identified in #113 (comment).

@marlitas
Copy link
Contributor

This is on @pixelzoom's list. It is unclear that it needs to be in subgroups. We are moving to done discussing. Feel free to move it back to subgroups for any reason if you'd like.

@pixelzoom pixelzoom removed their assignment Dec 9, 2023
@pixelzoom
Copy link
Contributor Author

I haven't gotten to this in > 1 year. It's not a priority, and (honestly) not really something that I'm interested in. So unassigning and reverting to the "To Be Discussed" column on the Developer Meeting project board.

@marlitas
Copy link
Contributor

@pixelzoom I think the Developer Meeting project board is no longer active. I'll add this as a discussion topic for the next developer meeting and we can discuss priority of allocating resources to address it in the future.

@zepumph
Copy link
Member

zepumph commented Dec 14, 2023

@samreid mentioned it may be pretty straight forward when calling toFixed to assert that it is the same as toFixedPointString and then run local fuzzing to see if there are any instances in which they differ, to understand the scope of the bugginess of Utils.toFixed().

We aren't really sure on the priority though.

@samreid
Copy link
Member

samreid commented Dec 14, 2023

I'm testing this patch in aqua:

Subject: [PATCH] Update documentation, see https://github.com/phetsims/projectile-data-lab/issues/7
---
Index: js/Utils.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/Utils.js b/js/Utils.js
--- a/js/Utils.js	(revision da8f04fb4ba29c460000ffedb9716350896dafa1)
+++ b/js/Utils.js	(date 1702580013533)
@@ -551,9 +551,50 @@
    * @returns {string}
    */
   toFixed( value, decimalPlaces ) {
+
     const multiplier = Math.pow( 10, decimalPlaces );
     const newValue = Utils.roundSymmetric( value * multiplier ) / multiplier;
-    return newValue.toFixed( decimalPlaces ); // eslint-disable-line bad-sim-text
+    const regularToFixed = newValue.toFixed( decimalPlaces ); // eslint-disable-line bad-sim-text
+
+    const newToFixed = Utils.toFixedCustom( value, decimalPlaces );
+    console.log( regularToFixed === newToFixed, regularToFixed, newToFixed );
+
+    return regularToFixed;
+  },
+
+  /**
+   * Decimal adjustment of a number.
+   *
+   * @param {String}  type  The type of adjustment.
+   * @param {Number}  value The number.
+   * @param {Integer} exp   The exponent (the 10 logarithm of the adjustment base).
+   * @returns {Number} The adjusted value.
+   */
+  decimalAdjust( type, value, exp ) {
+    // If the exp is undefined or zero...
+    if ( typeof exp === 'undefined' || +exp === 0 ) {
+      return Math[ type ]( value );
+    }
+    value = +value;
+    exp = +exp;
+    // If the value is not a number or the exp is not an integer...
+    if ( isNaN( value ) || !( typeof exp === 'number' && exp % 1 === 0 ) ) {
+      return NaN;
+    }
+    // Shift
+    value = value.toString().split( 'e' );
+    value = Math[ type ]( +( value[ 0 ] + 'e' + ( value[ 1 ] ? ( +value[ 1 ] - exp ) : -exp ) ) );
+    // Shift back
+    value = value.toString().split( 'e' );
+    return +( value[ 0 ] + 'e' + ( value[ 1 ] ? ( +value[ 1 ] + exp ) : exp ) );
+  },
+
+  round10( value, exp ) {
+    return Utils.decimalAdjust( 'round', value, exp );
+  },
+
+  toFixedCustom( value, digits ) {
+    return Utils.round10( value, -digits ).toFixed( digits );
   },
 
   /**

I'm through the letter 'c' and so far all values are the same. I tested the value pointed out above and saw that it corrected the problem:

phet.dot.Utils.toFixed( 35.855, 2 )
> false '35.85' '35.86'

@zepumph zepumph self-assigned this Dec 14, 2023
@zepumph
Copy link
Member

zepumph commented Dec 14, 2023

@samreid and I will discuss the discrepancies that he is finding.

@samreid
Copy link
Member

samreid commented Dec 14, 2023

Results of local aqua:


Sim errors (dev):
collision-lab
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 0.00 !== -0.01
collision-lab
Uncaught Error: Assertion failed: reentry detected, value=Vector2(-0.0050000000000003375, 0.495), oldValue=Vector2(-0.005, 0.495)
Error: Assertion failed: toFixedCustom should match regular toFixed, 0.00 !== -0.01
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (BallValuesPanelNumberDisplay.js:83:31)
    at numberFormatter (NumberDisplay.ts:395:18)
    at valueToString (NumberDisplay.ts:219:28)
    at derivation (DerivedProperty.ts:51:11)
    at getDerivedValue (DerivedProperty.ts:174:17)
    at listener (TinyEmitter.ts:123:8)
    at emit (ReadOnlyProperty.ts:329:22)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
Error: Assertion failed: reentry detected, value=Vector2(-0.0050000000000003375, 0.495), oldValue=Vector2(-0.005, 0.495)
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (ReadOnlyProperty.ts:325:14)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
    at set (Property.ts:54:10)
    at  (Ball.js:255:31)
    at dragToPosition (BallNode.js:207:13)
    at _start (DragListener.ts:352:26)
    at callback (PressListener.ts:729:16)
    at apply (PhetioAction.ts:162:16)
coulombs-law
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 0.0 !== -0.1
Error: Assertion failed: toFixedCustom should match regular toFixed, 0.0 !== -0.1
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (ISLCObjectNode.js:127:39)
    at _a11yMapPDOMValue (AccessibleValueHandler.ts:527:31)
    at _getMappedValue (AccessibleValueHandler.ts:383:31)
    at listener (ReadOnlyProperty.ts:425:4)
    at link (AccessibleValueHandler.ts:395:33)
    at  (AccessibleSlider.ts:72:6)
    at  (ISLCObjectNode.js:168:4)
fourier-making-waves
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, -0.2 !== -0.3
Error: Assertion failed: toFixedCustom should match regular toFixed, -0.2 !== -0.3
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (TickLabelSet.ts:75:56)
    at createLabel (TickLabelSet.ts:152:46)
    at callback (ChartTransform.ts:107:6)
    at forEachSpacing (TickLabelSet.ts:135:24)
    at update (TickLabelSet.ts:122:11)
    at setSpacing (DomainChartNode.ts:242:20)
    at callback (Multilink.ts:128:6)
    at  (Multilink.ts:184:11)
gas-properties
Uncaught Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (IdealGasLawContainer.ts:230:14)
    at getOpeningLeft (IdealGasLawContainer.ts:248:55)
    at getOpeningWidth (IdealGasLawContainer.ts:114:56)
    at derivation (DerivedProperty.ts:51:11)
    at getDerivedValue (DerivedProperty.ts:174:17)
    at listener (TinyEmitter.ts:123:8)
    at emit (ReadOnlyProperty.ts:329:22)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
gases-intro
Uncaught Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (IdealGasLawContainer.ts:230:14)
    at getOpeningLeft (IdealGasLawContainer.ts:248:55)
    at getOpeningWidth (IdealGasLawContainer.ts:114:56)
    at derivation (DerivedProperty.ts:51:11)
    at getDerivedValue (DerivedProperty.ts:174:17)
    at listener (TinyEmitter.ts:123:8)
    at emit (ReadOnlyProperty.ts:329:22)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
gases-intro
Uncaught Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
Error: Assertion failed: openingLeft 3000 must be <= openingRight -2000
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (IdealGasLawContainer.ts:230:14)
    at getOpeningLeft (IdealGasLawContainer.ts:248:55)
    at getOpeningWidth (IdealGasLawContainer.ts:179:32)
    at setWidth (IdealGasLawContainer.ts:196:9)
    at resizeImmediately (ContainerResizeDragListener.ts:47:20)
    at _dragListener (PressListener.ts:526:9)
    at call (DragListener.ts:296:35)
    at apply (PhetioAction.ts:162:16)
    at execute (DragListener.ts:447:21)
graphing-quadratics
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, -2.87 !== -2.88
Error: Assertion failed: toFixedCustom should match regular toFixed, -2.87 !== -2.88
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (CoordinatesNode.ts:50:38)
    at derivation (DerivedProperty.ts:51:11)
    at getDerivedValue (DerivedProperty.ts:174:17)
    at listener (TinyEmitter.ts:123:8)
    at emit (ReadOnlyProperty.ts:329:22)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
gravity-and-orbits
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 4.815336871508379e+24 !== 4.81533687150838e+24
Error: Assertion failed: toFixedCustom should match regular toFixed, 4.815336871508379e+24 !== 4.81533687150838e+24
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (Utils.js:924:17)
    at roundToInterval (ValueChangeSoundPlayer.ts:52:60)
    at constrainValue (ValueChangeSoundPlayer.ts:225:39)
    at playSoundIfThresholdReached (SliderTrack.ts:155:32)
    at handleTrackEvent (SliderTrack.ts:168:8)
    at _start (DragListener.ts:352:26)
    at callback (PressListener.ts:729:16)
greenhouse-effect
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, -273.1 !== -273.2
Error: Assertion failed: toFixedCustom should match regular toFixed, -273.1 !== -273.2
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (NumberDisplay.ts:146:21)
    at numberFormatter (NumberDisplay.ts:395:18)
    at valueToString (NumberDisplay.ts:192:13)
    at derivation (DerivedProperty.ts:51:11)
    at getDerivedValue (DerivedProperty.ts:105:25)
    at  (NumberDisplay.ts:191:30)
    at  (ThermometerAndReadout.ts:233:24)
    at createNode (GroupItemOptions.ts:33:16)
interaction-dashboard
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 4694728.753291830 !== 4694728.753291829
Error: Assertion failed: toFixedCustom should match regular toFixed, 4694728.753291830 !== 4694728.753291829
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (Utils.js:924:17)
    at roundToInterval (ValueChangeSoundPlayer.ts:52:60)
    at constrainValue (ValueChangeSoundPlayer.ts:225:39)
    at playSoundIfThresholdReached (Slider.ts:251:34)
    at drag (SliderTrack.ts:172:16)
    at _dragListener (PressListener.ts:526:9)
    at call (DragListener.ts:296:35)
least-squares-regression
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, NaN !== 0.0
least-squares-regression
Uncaught Error: Assertion failed: reentry detected, value=[object Object], oldValue=[object Object]
Error: Assertion failed: toFixedCustom should match regular toFixed, NaN !== 0.0
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (GraphAxesNode.js:285:54)
    at  (GraphAxesNode.js:76:8)
    at  (LeastSquaresRegressionScreenView.js:187:22)
    at listener (TinyEmitter.ts:123:8)
    at emit (ReadOnlyProperty.ts:329:22)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
    at set (Property.ts:54:10)
Error: Assertion failed: reentry detected, value=[object Object], oldValue=[object Object]
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (ReadOnlyProperty.ts:325:14)
    at _notifyListeners (ReadOnlyProperty.ts:276:13)
    at unguardedSet (ReadOnlyProperty.ts:260:11)
    at set (Property.ts:54:10)
    at  (ComboBoxListBox.ts:113:20)
    at apply (PhetioAction.ts:162:16)
    at execute (ComboBoxListBox.ts:135:19)
    at inputEvent (Input.ts:1907:69)
    at dispatchToListeners (Input.ts:1947:11)
ph-scale
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 0.000209999999999999982 !== 0.000209999999999999954
Error: Assertion failed: toFixedCustom should match regular toFixed, 0.000209999999999999982 !== 0.000209999999999999954
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (Utils.js:924:17)
    at roundToInterval (GraphIndicatorDragListener.ts:106:32)
    at doDrag (GraphIndicatorDragListener.ts:67:35)
    at _dragListener (PressListener.ts:526:9)
    at call (DragListener.ts:296:35)
    at apply (PhetioAction.ts:162:16)
    at execute (DragListener.ts:447:21)
xray-diffraction
Uncaught Error: Assertion failed: toFixedCustom should match regular toFixed, 0.087266462599716460 !== 0.087266462599716474
Error: Assertion failed: toFixedCustom should match regular toFixed, 0.087266462599716460 !== 0.087266462599716474
    at window.assertions.assertFunction (http://localhost/assert/js/assert.js:28:13)
    at assert (Utils.js:561:14)
    at toFixed (Utils.js:614:29)
    at toFixedNumber (Utils.js:924:17)
    at roundToInterval (NumberControl.ts:262:29)
    at constrainValue (SliderTrack.ts:150:31)
    at handleTrackEvent (SliderTrack.ts:168:8)
    at _start (DragListener.ts:352:26)
    at callback (PressListener.ts:729:16)
    at apply (PhetioAction.ts:162:16)

failing sims: http://localhost/aqua/fuzz-lightyear/?loadTimeout=30000&testTask=true&ea&audio=disabled&testDuration=10000&brand=phet&fuzz&testSims=coulombs-law,fourier-making-waves,gas-properties,gases-intro,graphing-quadratics,gravity-and-orbits,greenhouse-effect,interaction-dashboard,least-squares-regression,ph-scale,xray-diffraction

@zepumph
Copy link
Member

zepumph commented Dec 14, 2023

With this patch, we found a couple cases where toFixedPointString does not behave correctly:

  1. With scientific notation provided with an e. Like acid-base-soutions:
    • inputs: 1e-7, 10
    • Utils.toFixed: 0.0000001000
    • toFixedPointString: 1e-7.0000000000
  2. many 9s in a row that need to round: Like bamboo:
    • inputs: 2.7439999999999998, 7
    • Utils.toFixed: 2.7440000
    • toFixedPointString: 2.74399910
  3. just a super buggy confusing case: Like beers-law-lab:
    • inputs: 0.396704, 2
    • Utils.toFixed: 0.40
    • toFixedPointString: 0.310

I'll stop being formal in formatting and put some more here:


// template
sim:
value
digits
Utils.toFixed
toFixedPointString()

bending light:
1.0002929999999999
 7
 1.0002930
 1.00029210


blackbody:
 0.4996160344827586
 3
 0.500
 0.4910

buoyancy
 99.99999999999999
 2
 100.00
 99.910

charges-and-fields
 2.169880191815152
 3
 2.170
 2.1610

circuit-construction-kit-black-box-study
 1.0999999999999999e-7
 1
 0.0
 1.1


Subject: [PATCH] use containsKey, https://github.com/phetsims/my-solar-system/issues/318
---
Index: js/Utils.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/js/Utils.js b/js/Utils.js
--- a/js/Utils.js	(revision da8f04fb4ba29c460000ffedb9716350896dafa1)
+++ b/js/Utils.js	(date 1702585802038)
@@ -7,6 +7,7 @@
  */
 
 import dot from './dot.js';
+import toFixedPointString from './toFixedPointString.js';
 import Vector2 from './Vector2.js';
 import Vector3 from './Vector3.js';
 
@@ -553,7 +554,12 @@
   toFixed( value, decimalPlaces ) {
     const multiplier = Math.pow( 10, decimalPlaces );
     const newValue = Utils.roundSymmetric( value * multiplier ) / multiplier;
-    return newValue.toFixed( decimalPlaces ); // eslint-disable-line bad-sim-text
+    const regularToFixed = newValue.toFixed( decimalPlaces ); // eslint-disable-line bad-sim-text
+
+    const cmToFixed = toFixedPointString( value, decimalPlaces );
+    assert && assert( regularToFixed === cmToFixed, 'different from toFixedPointString', value, decimalPlaces, regularToFixed, cmToFixed );
+
+    return regularToFixed;
   },
 
   /**

zepumph added a commit to phetsims/molarity that referenced this issue Dec 14, 2023
zepumph added a commit that referenced this issue Dec 14, 2023
@samreid
Copy link
Member

samreid commented Dec 22, 2023

Everything in the commit looks great, thanks! Regarding performance, 1400ms is for calling 1000000 times, so it is just 0.0014ms per call and not something that should cause concern (particularly since this is not often called in an iterative model loop). My only review comment is that WebStorm is showing:

image

So I'm not sure why it is not a tsc error. I wonder if we just want to get rid of those large numbers?

zepumph added a commit to phetsims/alpenglow that referenced this issue Dec 22, 2023
@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

I kinda liked having one in that space, just in case Big had an awkward implementation (or at least different) for that class of numbers. Ready to close?

@zepumph zepumph assigned samreid and unassigned zepumph Dec 22, 2023
@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

Looks like serving the mjs file on sparky with nginx is resulting in this error:

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of 
"application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.

A google search showed how to solve it: https://kas.kim/blog/failed-to-load-module-script

zepumph added a commit to phetsims/perennial that referenced this issue Dec 22, 2023
@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

Adding our first mjs file has caused some server problems. I had to patch mime types for withServer too. I'll go look for more mime types.

@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

I didn't find any others, because js isn't supported in this guy:

https://github.com/phetsims/chipper/blob/b4f9348651551c65dbb38900cc59e7e2ecbac5a0/js/common/loadFileAsDataURI.js#L20-L33

@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

Oh, I'll look into bayes for phettest.

In https://stackoverflow.com/questions/61797225/using-mjs-file-extension-js-modules I found a good solution that worked when I put it at the .htaccess above phettest and deployed dev/rc versions. It should work from here.

@zepumph
Copy link
Member

zepumph commented Dec 22, 2023

I'm seeing an assertion come in about an undefined for decimal places:

capacitor-lab-basics : fuzz : unbuilt
http://128.138.93.172/continuous-testing/ct-snapshots/1703282283784/capacitor-lab-basics/capacitor-lab-basics_en.html?continuousTest=%7B%22test%22%3A%5B%22capacitor-lab-basics%22%2C%22fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1703282283784%22%2C%22timestamp%22%3A1703283021947%7D&brand=phet&ea&fuzz
Query: brand=phet&ea&fuzz
Uncaught Error: Assertion failed: decimal places must be an integer: undefined
Error: Assertion failed: decimal places must be an integer: undefined
at window.assertions.assertFunction (http://128.138.93.172/continuous-testing/ct-snapshots/1703282283784/assert/js/assert.js:28:13)
at assert (Utils.js:556:14)
at toFixed (DragHandleValueNode.js:68:33)
at setValue (DragHandleValueNode.js:55:9)
at (PlateSeparationDragHandleNode.js:65:21)
at (CLBCircuitNode.js:103:42)
at (CapacitanceCircuitNode.js:22:4)
at (CapacitanceScreenView.js:38:34)
at (CapacitanceScreen.js:41:15)
at createView (Screen.ts:307:22)
[URL] http://128.138.93.172/continuous-testing/aqua/html/sim-test.html?url=..%2F..%2Fct-snapshots%2F1703282283784%2Fcapacitor-lab-basics%2Fcapacitor-lab-basics_en.html&simQueryParameters=brand%3Dphet%26ea%2

east-squares-regression : multitouch-fuzz : unbuilt
http://128.138.93.172/continuous-testing/ct-snapshots/1703283437941/least-squares-regression/least-squares-regression_en.html?continuousTest=%7B%22test%22%3A%5B%22least-squares-regression%22%2C%22multitouch-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1703283437941%22%2C%22timestamp%22%3A1703283816403%7D&brand=phet&ea&fuzz&fuzzPointers=2&supportsPanAndZoom=false
Query: brand=phet&ea&fuzz&fuzzPointers=2&supportsPanAndZoom=false
Uncaught Error: Assertion failed: decimal places must be an integer: 1.3010299956639813
Error: Assertion failed: decimal places must be an integer: 1.3010299956639813
at window.assertions.assertFunction (http://128.138.93.172/continuous-testing/ct-snapshots/1703283437941/assert/js/assert.js:28:13)
at assert (Utils.js:556:14)
at toFixed (GraphAxesNode.js:285:54)
at (GraphAxesNode.js:76:8)
at (LeastSquaresRegressionScreenView.js:187:22)
at listener (TinyEmitter.ts:123:8)
at emit (ReadOnlyProperty.ts:329:22)
at _notifyListeners (ReadOnlyProperty.ts:276:13)
at unguardedSet (ReadOnlyProperty.ts:260:11)
at set (Property.ts:54:10)
[URL] http://128.138.93.172/continuous-testing/aqua/html/sim-test.html?url=..%2F..%2Fct-snapshots%2F1703283437941%2Fleast-squares-regression%2Fleast-squares-regression_en.html&simQueryParameters=brand%3Dphet%26ea%26fuzz%26fuzzPointers%3D2%26supportsPanAndZoom%3Dfalse&testInfo=%7B%22test%22%3A%5B%22least-squares-regression%22%2C%22multitouch-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1703283437941%22%2C%22timestamp%22%3A1703283816403%7D
[NAVIGATED] http://128.138.93.172/continuous-testing/aqua/html/sim-test.html?url=..%2F..%2Fct-snapshots%2F1703283437941%2Fleast-squares-regression%2Fleast-squares-regression_en.html&simQueryParameters=brand%3Dphet%26ea%26fuzz%26fuzzPointers%3D2%26supportsPanAndZoom%3Dfalse&testInfo=%7B%22test%22%3A%5B%22least-squares-regression%22%2C%22multitouch-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1703283437941%22%2C%22timestamp%22%3A1703283816403%7D
[NAVIGATED] about:blank
[NAVIGATED] http://128.138.93.172/continuous-testing/ct-snapshots/1703283437941/least-squares-regression/least-squares-regression_en.html?continuousTest=%7B%22test%22%3A%5B%22least-squares-regression%22%2C%22multitouch-fuzz%22%2C%22unbuilt%22%5D%2C%22snapshotName%22%3A%22snapshot-1703283437941%22%2C%22timestamp%22%3A1703283816403%7D&brand=phet&ea&fuzz&fuzzPointers=2&supportsPanAndZoom=false
[CONSOLE] enabling assert
[CONSOLE] continuous-test-load

@zepumph zepumph assigned zepumph and unassigned samreid Dec 22, 2023
zepumph added a commit to phetsims/capacitor-lab-basics that referenced this issue Dec 22, 2023
zepumph added a commit to phetsims/least-squares-regression that referenced this issue Dec 22, 2023
@zepumph
Copy link
Member

zepumph commented Jan 2, 2024

Ok, CT is looking clear. @samreid can you please review?

@zepumph zepumph assigned samreid and unassigned zepumph Jan 2, 2024
@samreid
Copy link
Member

samreid commented Jan 2, 2024

Everything seems great, nice work @zepumph. Closing.

@samreid samreid closed this as completed Jan 2, 2024
@phet-dev
Copy link
Contributor

phet-dev commented Jan 3, 2024

Reopening because there is a TODO marked for this issue.

@samreid
Copy link
Member

samreid commented Jan 3, 2024

The remaining todo is in ScientificNotationNode:

    if ( options.exponent !== null ) {

      // M x 10^E, where E is options.exponent
      //TODO https://github.com/phetsims/dot/issues/113 division here and in Utils.toFixed can result in floating-point error that affects rounding
      mantissa = Utils.toFixed( value / Math.pow( 10, options.exponent ), options.mantissaDecimalPlaces );
      exponent = options.exponent.toString();
    }

This TODO was added in phetsims/scenery-phet@5a03225. I also commented on a related TODO in ScientificNotationNode in phetsims/scenery-phet#613

@zepumph and I changed Utils.toFixed to use big.js, which describes itself as "A small, fast JavaScript library for arbitrary-precision decimal arithmetic.". @pixelzoom can you please review the TODOs in ScientificNotationNode and check their status? Please zoom consult with me and/or @zepumph as needed.

@samreid samreid assigned pixelzoom and unassigned samreid Jan 3, 2024
@pixelzoom
Copy link
Contributor Author

pixelzoom commented Jan 3, 2024

@pixelzoom can you please review the TODOs in ScientificNotationNode and check their status?

Can do. But it looks like you've assigned that work to me in phetsims/scenery-phet#613. So I have adjusted the TODO and will close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants