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

The implementation of trigonometric functions should be aligned with the JavaScript backend #1488

Open
Lampese opened this issue Jan 16, 2025 · 2 comments

Comments

@Lampese
Copy link
Collaborator

Lampese commented Jan 16, 2025

I think the current trigonometric functions should be replaced with implementations consistent with V8, so that we can directly inline them into Math on the JavaScript backend.

@Lampese
Copy link
Collaborator Author

Lampese commented Jan 16, 2025

cc @tonyfettes @Kaida-Amethyst Is this plan reasonable?

@Kaida-Amethyst
Copy link
Contributor

Kaida-Amethyst commented Jan 16, 2025

I think it would be beneficial. The current Moonbit implementation seems to have precision issues, as demonstrated by the following code and results --- the hex values of sin(π) and cos(π/2):

Moonbit (math from core):

fn main {
  let x = 3.141592653589793  // π
  let sin_x = @math.sin(x)
  let isin_x = BigInt::from_int64(sin_x.reinterpret_as_int64()).to_hex(uppercase=false)
  println("sin(\{x}) = \{sin_x}(0x\{isin_x})")
  let x = 1.5707963267948966c   // π/2
  let cos_x = @math.cos(x)
  let icos_x = BigInt::from_int64(cos_x.reinterpret_as_int64()).to_hex(uppercase=false)
  println("cos(\{x}) = \{cos_x}(0x\{icos_x})")
}

Output:

sin(3.141592653589793) = 1.2246703776017889e-16(0x3ca1a63c78000000)
cos(1.5707963267948966) = 6.123351888008944e-17(0x3c91a63c78000000)

JavaScript ( run by node):

function doubleToHex(double) {
    const buffer = new ArrayBuffer(8);
    const view = new DataView(buffer);
    view.setFloat64(0, double);

    let hex = '';
    for (let i = 0; i < 8; i++) {
        const byte = view.getUint8(i);
        hex += byte.toString(16).padStart(2, '0');
    }

    return hex;
}

let x1 = 3.141592653589793;   // π
let sin_x = Math.sin(x1);
let isin_x = doubleToHex(sin_x);
console.log('sin(' + x1 + ') = ' + sin_x + '(0x' + isin_x+')');

let x2 = 1.5707963267948966     // π/2
let cos_x = Math.cos(x2);
let icos_x = doubleToHex(cos_x);
console.log('cos(' + x2 + ') = ' + cos_x + '(0x' + icos_x+')');

Output:

sin(3.141592653589793) = 1.2246467991473532e-16(0x3ca1a62633145c07)
cos(1.5707963267948966) = 6.123233995736766e-17(0x3c91a62633145c07)

C (gcc, glibc):

#include <math.h>
#include <stdio.h>

int main() {
  double x1 = 3.141592653589793;   // π
  double sin_x = sin(x1);
  unsigned long isin_x = *(unsigned long *)&sin_x;
  printf("sin(%lf) = %lf(0x%lx)\n", x1, sin_x, isin_x);

  double x2 = 1.5707963267948966;     // π/2
  double cos_x = cos(x2);
  unsigned long icos_x = *(unsigned long *)&cos_x;
  printf("cos(%lf) = %lf(0x%lx)\n", x2, cos_x, icos_x);
  return 0;
}

Output:

sin(3.141593) = 0.000000(0x3ca1a62633145c07)
cos(1.570796) = 0.000000(0x3c91a62633145c07)

Observations:

  • The hex values of the results show discrepancies between Moonbit, Javascript, and glibc.
  • Moonbit's results (0x3ca1a63c78000000 and 0x3c91a63c78000000) differ from Javascript and glibc (0x3ca1a62633145c07 and 0x3c91a62633145c07), indicating potential precision issues in the current implementation.

Adopting V8's approach could help resolve these discrepancies and improve consistency across platforms.

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

2 participants