project-mahiwa / mahiwa-backend

mahiwaのバックエンド
GNU Lesser General Public License v2.1
0 stars 0 forks source link

[🐛Bug]: 三角関数の返り値が必ず0になる? #91

Closed usuyuki closed 9 months ago

usuyuki commented 9 months ago

🐛 概要

mahiwa-backendで直接読んだ場合は

cos(0.0)1.00
cos(1.0)0.54

のようになるが,Rustから呼ぶと

cos(0.0): 0.00
cos(1.0): 0.00

になる.

原因

備考

usuyuki commented 9 months ago

これ返り値は来てるわけだから,printDoubleで型キャスト事故ってる気がする.

いや,

  Serial.print("cos(0.0)");
  Serial.println(cos(0.0));
  Serial.print("cos(1.0)");
  Serial.println(cos(1.0));

でやった方は

cos(0.0)1.00
cos(1.0)0.54

ちゃんと出てるので,違う?

オーバーロードしまくりマクロ使用なので実際どうなってるかわかりにくい.

usuyuki commented 9 months ago
    if (arduino::cos(1.0) != 0.00) {
        serial::println("cos(1.0)is not 0.00 ");
    }

serial::println("cos(1.0)is not 0.00 ");に到達したので,結果自体は正しく取れてそう.

usuyuki commented 9 months ago
     serial::print("print ");
    serial::println("println");
    serial::println("print UTF-8 : 𰻞𰻞麺");
    serial::println("print UTF-8 : 🍆");

    serial::print("printInt(10):");
    serial::print_int(10);
    serial::println("");

    serial::print("printLong(3147483647):");
    // int32の最大値2147483647を超えた値を入れてみる
    serial::print_long(3147483647);
    serial::println("");

    serial::print("printFloat(1.1111):");
    serial::print_float(1.1111);
    serial::println("");

    serial::print("printDouble(1.123456789012345678901):");
    // float32の最大値
    serial::print_double(1.123456789012345678901);
    serial::println("");
Project Mahiwa : WebAssembly launch
print println
print UTF-8 : 𰻞𰻞麺
print UTF-8 : 🍆
printInt(10):10
printLong(3147483647):-1147483649
printFloat(1.1111):1.11
printDouble(1.123456789012345678901):1.12
Project Mahiwa : WebAssembly done

Longが壊れている,floatとdoubleも結果が丸められている.

printDouble(1.123456789012345678901):はある程度は取れてるので,sinの結果が正しいことと矛盾する.なぜ.

usuyuki commented 9 months ago
 Serial.print(String(num, 10));

にしたら

printInt(10):10
printLong(3147483647):-1147483649
printFloat(1.1111):1.1110999584
printDouble(1.123456789012345678901):1.1234567890

確かに取れてるが,壊れているところは壊れる. ありのままをプリントしたい.

usuyuki commented 9 months ago

arduinoではsprintfでfloatとか出せないらしい

https://kurobekoblog.com/arduino_sprint

usuyuki commented 9 months ago

ESP32版のArduinoにはprintfが入っているらしい

usuyuki commented 9 months ago

dtostrfを組み合わせるとできそう.ちょっと厄介だが.

usuyuki commented 9 months ago

dtostrfはデフォで入ってるはずが入ってない.

usuyuki commented 9 months ago

実行時に桁数も指定するのが良さそう.

usuyuki commented 9 months ago
    serial::print_double(1.123456789012345678901, 30);

printDouble(1.123456789012345678901):1.123456789012345691247674039914

後ろの値が壊れている……doubleなので読めるはずだが.

usuyuki commented 9 months ago

Longのオーバーフローは謎

→謎だが,仕様でintとlongの最大値は同じらしい https://learn.microsoft.com/ja-jp/cpp/c-language/cpp-integer-limits?view=msvc-170

明らかにおかしいが,仕様なのでしょうがない.

usuyuki commented 9 months ago

コード

fn _start() {
    // Arduino関数の動作確認
    /*
     * Serial
     */
    serial::print("print ");
    serial::println("println");
    serial::println("print UTF-8 : 𰻞𰻞麺");
    serial::println("print UTF-8 : 🍆");

    // intとlongで表せる範囲が同じ.←直感と反するが仕様である
    serial::print("printInt(10):");
    serial::print_int(10);
    serial::println("");

    serial::print("printLong(1000):");
    serial::print_long(1000);
    serial::println("");

    serial::print("printLong(2247483647)❌:");
    // longの最大値2147483647を超えた値を入れてみる(オーバーフロー)
    serial::print_long(2247483647);
    serial::println("");

    serial::print("printFloat(1.1111):");
    serial::print_float(1.1111, 4);
    serial::println("");

    serial::print("printFloat(1.123456789012345)❌:");
    // float32の最大値を超えた値を入れてみる
    serial::print_float(1.123456789012345, 15);
    serial::println("");

    serial::print("printDouble(1.123456789012345):");
    serial::print_double(1.123456789012345, 15);
    serial::println("");
}

結果

Project Mahiwa : WebAssembly launch
print println
print UTF-8 : 𰻞𰻞麺
print UTF-8 : 🍆
printInt(10):10
printLong(1000):1000
printLong(2247483647)❌:-2047483649
printFloat(1.1111):1.1111
printFloat(1.123456789012345)❌:1.123456835746765
printDouble(1.123456789012345):1.123456789012345
Project Mahiwa : WebAssembly done
usuyuki commented 9 months ago

ちゃんとオーバーフローが期待できる場所はオーバーフローしてて問題なさそうに修正できた.

usuyuki commented 9 months ago

新しく作っても結果変わらず

cos(0.0): 0.000000
cos(1.0): 0.000000
sin(1.0): 0.000000
sin(0.0): 0.000000
tan(1.0): 0.000000
tan(1.1): 0.000000
usuyuki commented 9 months ago

本当の定義をメソッドジャンプしてみると

extern double sin (double);

とdouble,doubleになっており,型も問題なさそう.

usuyuki commented 9 months ago

未解決.

usuyuki commented 9 months ago

Goではちゃんとcosの値が取れた.ただし直後にpanicする

cos(1.0):0.540302Guru Meditation Error: Core  1 panic'ed (Double exception). 
usuyuki commented 9 months ago

これはprint側に問題がありそう

printFloat(1.1111):1.1111Guru Meditation Error: Core  1 panic'ed (Unhandled debug exception). 
Debug exception reason: Stack canary watchpoint triggered (wasm3) 
usuyuki commented 9 months ago

https://github.com/wasm3/wasm3/issues/102#issuecomment-586643752

これっぽい

This means that the interpreter has run out of the (native) stack. One option is to run an interpreter in a separate task with a larger stack size.

usuyuki commented 9 months ago

floatが入らないレベルでスタックサイズが小さいってこと?

usuyuki commented 9 months ago

https://github.com/project-mahiwa/mahiwa-frontend-go/issues/29

usuyuki commented 9 months ago
    let cos2 = arduino::cos(1.0);
    let cos2x100 = (cos2 * 100.0) as i32;
    serial::print_int(cos2x100);

の結果が

cos(1.0): 0

やはりarudino::cosの返り値がおかしい 一方でgoでは取れているのでbackendの実装は壊れてなさそう

usuyuki commented 9 months ago

どちらもf64 f64なので型には問題ないが……

最悪f64の受け取りはそのままで、内部的にはいったんintに変えて、backendでfloatに戻すとかもありかも……

usuyuki commented 9 months ago

おそらくWebAssemblyが間に挟まってることで起きるのだが、そこは見れないので難しい。

goでは動いていることを踏まえて、backendの実装ミスではないので、一旦保留する。