Си диез / Говнокод #29152 Ссылка на оригинал

0

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
// https://github.com/dotnet/runtime/issues/117233#issuecomment-3028066225

// Issue: Math.Pow relies directly on the OS pow implementation

// Location: [src/coreclr/classlibnative/float/floatdouble.cpp lines 232‑236] and [src/coreclr/classlibnative/float/floatsingle.cpp lines 207‑211]

// COMDouble::Pow and COMSingle::Pow simply call pow/powf from the C runtime. On Windows 11 Insider Preview (build 27881.1000),
// these functions can return incorrect results (e.g., Math.Pow(-1, 2) giving -1). The JIT also uses these functions for constant folding, causing
// wrong constants to be embedded at compile time.

// Suggested Fix: Introduce a managed fallback in COMDouble::Pow/COMSingle::Pow that handles negative bases with integral exponents, bypassing the faulty system call.

//A simple approach:

FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
{
    FCALL_CONTRACT;

    if ((x < 0.0) && (y == floor(y)))
    {
        double absResult = pow(-x, y);
        return fmod(fabs(y), 2.0) == 1.0 ? -absResult : absResult;
    }

    return pow(x, y);
}

// Suggested Implementation:

// Add the following code to src/coreclr/classlibnative/float/floatdouble.cpp below line 234 before the return pow:

if ((x < 0.0) && (y == floor(y)))
{
    double result = pow(-x, y);

    if (fmod(fabs(y), 2.0) != 0.0)
    {
        result = -result;
    }

    return result;
}

// Add the following code to src/coreclr/classlibnative/float/floatsingle.cpp below line 209 before the return powf:

if ((x < 0.0f) && (y == floorf(y)))
{
    float result = powf(-x, y);

    if (fmodf(fabsf(y), 2.0f) != 0.0f)
    {
        result = -result;
    }

    return result;
}

// Add the following code to src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs below line 1124:

[Fact]
public static void Pow_NegativeBaseEvenExponent_ReturnsPositive()
{
    Assert.Equal(1.0, Math.Pow(-1, 2));
    Assert.Equal(16.0, Math.Pow(-2, 4));
}

Вот к чему плавучий петух приводит!

Запостил: j123123 j123123, (Updated )

Комментарии (22) RSS

  • В шарпе еще есть какая-то функция возведения для комплексных чисел, можно наверное ее использовать, брать действительную часть
    https://learn.microsoft.com/uk-ua/dotnet/api/system.numerics.complex.pow?view=net-10.0
    public static System.Numerics.Complex Pow(System.Numerics.Complex value, double power);

    Только вот какого хрена там первый аргумент комплесный, второй это обычный дабл? У меня в Си у "cpow" оба аргумента комплексные:
    double complex cpow(double complex x, double complex z);

    Именно поэтому я за Си
    Ответить
        • Получается, что теперь нельзя заглавную I использовать в качестве имени переменной или макроса?
          Ответить
            • Всё, вижу:

              #ifdef __GNUC__
              #define	_Complex_I	((float _Complex)1.0i)
              #endif
              
              #define	complex		_Complex
              #define	I		_Complex_I


              Т. е. на уровне языка I не зашкварена, есть просто суффикс для литералов: 1.23i. Значит, никакой необходимости в #define I нету.
              Ответить
            • --место--для-шутки-про-min-max-и-windows.h--
              Ответить
              • Windows SDK — это ад. Некоторые хедеры ломают определения из хедеров самого компилятора, так что результат компиляции может зависеть от порядка #include.

                Это авгиевы конюшни.
                Ответить
                • Макросню в принципе легко сломать, можно случайно библиотечный макрос переопределить и ловить багры:
                  #define A puts("hui")
                  #define B A;A;
                  
                  int main(){
                      B
                      #define A puts("pizda")
                      B
                      #undef A
                      B //всё
                  }
                  Ответить
                  • При желании можно и хуй сломать.

                    Досадно, что макросы SDK и макросы компилятора ломают друг друга.
                    Ответить
      • Это кто-то забыл, что макросня должна писаться с болшой буквы
        Ответить
        • Макрос с большой буквы
          Слово "макрос" пишется с большой буквы
          Ответить
        • Хорошо, тут макрос написали с маленькой. Но макрос не волшебная палочка, он разворачивается во встроенный тип _Complex.
          Ответить
          • А можно для тех, кто в кулинарном техникуме учился: нахуя нужны комплексные числа вообще? В чем поинт?
            Ответить
            • Помнишь, как в начальной школе решали задачи, избегая отрицательных чисел и дробных чисел? Получалось, но в голове приходилось прокручивать кучу «ифов».

              Так вот с комплексными что-то похожее: они позволяют некоторые задачи решать единой формулой без ветвления.
              Ответить
  • >On Windows 11 Insider Preview (build 27881.1000),
    // these functions can return incorrect results

    .net: write once, test everywhere. Сука.
    Ответить
  • Это очень смешно))

    Это как если бы оператор "+" у двух четрехбайтовых целых зависел от версии либси
    Ответить
    • g: pentium fdiv bug

      А ты над библиотекой смеёшься...

      К слову, в первая партия 80386 оказалась бракованной: на ней целочисленное деление 32-битных чисел (в смысле не когда 32 бита в DX+AX, а когда делитель 32-битный) иногда давало неправильный результат. Эту партию процессоров промаркировали: «Только для 16-битных приложений!» Вторая партия была уже исправленной.

      А в «Пентиуме» ничего исправлять не стали, поэтому в библиотеках пришлось городить «fdiv workaround».
      Ответить
  • Я в своё время писал свою функцию для возведения вещественных чисел в дробную степень. Показатель степени через разложение в цепную дробь преобразовывал в обыкновенную дробь (с заданной точностью). Далее при отрицательном основании рассматривал варианты:

    1. Если знаменатель показателя степени чётный, посылал нахуй, ибо результат в этом случае должен быть чисто мнимым, а я писал для вещественных чисел.

    2. Если знаменатель показателя степени нечётный, то знак результата выбирал в зависимости от чётности числителя показателя степени.

    При положительном основании, естественно, проблем нет.

    То есть я доопределил операцию возведения в степень до предсказуемого результата, выбрав при дробном показателе самый очевидный корень.
    Ответить
    • > Показатель степени через разложение в цепную дробь преобразовывал в обыкновенную дробь (с заданной точностью).
      Т.е. ты подбирал числитель и знаменатель и по формуле a^(m/n)=(a^(1/n))^m решал? Ну ок, а дальше что? Например если надо посчитать 2^pi, находим некое рациональное приближение числа Пи, 223⁄71 допустим, получается что 2^(223/71)=(2^(1/71))^223, а как ты считал 2^(1/71)? Методом Ньютона?
      Ответить
      • Да тупо как exp((1/71)*log(2)). Меня устроила точность стандартной библиотеки.
        Ответить
    • Обесните откуда мнимость. Я знаю про путь через ряд тейлора с удобной производной от экспоненты, пока не понимаю, как он может дать мнимость.
      Ответить

Добавить комментарий

Я, guest, находясь в здравом уме и твердой памяти, торжественно заявляю:

    А не использовать ли нам bbcode?


    8