C# разрабатывал тайный фанат Джаваскрипта
200
30
Знаете, в чём разница этих двух картинок?
В строчке
dist = height / (plank * 2.0 - height) / Math.Cos(cam.fov * 0.5 - (bar * cam.fov /width));
dist = height / (plank * 2 - height) / Math.Cos(cam.fov / 2 - (bar * cam.fov / width));
Ну смотрите. Я большую часть времени программировал на Паскале.
Если пишу на Паскале
a/b, то получаю нормальное деление. ВСЕГДА.
a div b, то получаю целочисленное деление. ВСЕГДА.
Но если я пишу на C#, то он внезапно начинает играть в Вангу и решать за меня, чё я там такое хотел.
a/b он тебе преобразует и в целочисленное деление, и в нормальное, причём ЧСХ вообще без предупреждения, ни тебе ошибки, ни тебе warning.
Это напоминает мне офигенный опыт из Жаваскрипта, когда она выдавала бредовые результаты в одной из функций, потому что в каком-то параметре у меня была функция трёх переменных, в которую я забыл передать эту третью переменную. И Джаваскрипт усердно чёто-там наприводил и выплюнул, не дав мне ни ошибки, не предупреждения, нифига.
Я потратил три с половиной часа чтобы этот баг найти. Что там, что тут. Я умудрился найти математическое и тригонометрическое описание своей задачи и даже начал писать и выводить все формулы заново.
Хотя знал, что в коде они у меня правильные, потому что я этот код построчно перенёс, собственно, с Паскаля. Где всё клёво работало.
Спасибо большое Мелкомягкие за то, что в нормальном языке сделали шизоидный плавающий тип вычислений базового оператора
П.С. Ну я затестил полы тут. Буду щас тестить оптимизации всякие. Потому что фэпэс падает с 200 до 15. Потом добавлю существ с анимациями. Ну и в принципе готово.
VovkaKalibrovka сказал(а):↑жаль что на любом сайте по Си Шарпу ясно написано, что если a,b целые (int) то результат будет целым (int) а если a или b float то ответ float
Нажмите, чтобы раскрыть...Вот щас бы перед использованием весьма определённого и простейшего оператора деления искать чё он там делает.
А давайте мы для каждого токена будем так делать?
Вдруг если перед { написать 2 пробела, то она скипается каждый чётный цикл, а если 3 пробела, то каждый нечётный цикл, а если 1 пробел, то цикл просто не выполняется?
А вдруг если мы складываем дабл с интом, то получаем в ответе округлённый вверх результат деления инта на дабл? А вдруг если мы пишем
int d; это значит, что мы сделали класс cPowCannon с полем double p = 8; и методом public static int qwe(Point d) => 5846;
Kujivunia сказал(а):↑Вот щас бы перед использованием весьма определённого и простейшего оператора деления искать чё он там делает.
Нажмите, чтобы раскрыть...
Ну C# строго типизирован, в принципе логично что он не выплевывает float из операции над int
И да, в JS как раз бы не было такой проблемы, там бы все норм поделилось
Kujivunia сказал(а):↑Вот щас бы перед использованием весьма определённого и простейшего оператора деления искать чё он там делает.
А давайте мы для каждого токена будем так делать?
Вдруг если перед { написать 2 пробела, то она скипается каждый чётный цикл, а если 3 пробела, то каждый нечётный цикл, а если 1 пробел, то цикл просто не выполняется?
А вдруг если мы складываем дабл с интом, то получаем в ответе округлённый вверх результат деления инта на дабл? А вдруг если мы пишем
int d; это значит, что мы сделали класс cPowCannon с полем double p = 8; и методом public static int qwe(Point d) => 5846;
Нажмите, чтобы раскрыть...если б ты по языкам не прыгал а учил один то знал бы особенности своего языка
kremennik сказал(а):↑
Ну C# строго типизирован, в принципе логично что он не выплевывает float из операции над int
И да, в JS как раз бы не было такой проблемы, там бы все норм поделилось
Нажмите, чтобы раскрыть...Строго типизирован - это когда функция с типом возвращаемого значения double будет возвращать чистый double, а не делать
(double)((int)result)
kremennik сказал(а):↑
Сложно
Нажмите, чтобы раскрыть...Ну так в этом и претензия, какой шизоид вообще решил, что офигенной идеей будет сделать перегруженный оператор, который в половине случаев выплёвывает result, а в другой половине приведёт его к инту, а потом это приведение приведёт обратно в дабл (double)((int)result)
1)Ты сам явно не определил тип константы/переменой
Поэтому стоит почитать как ЯП поступает в этих случаях и что возвращает при простых мат операциях (неявное приведение типа).
2) А разве JS должен проверять что ты там забыл передать в функцию?
kremennik сказал(а):↑Ну C# строго типизирован, в принципе логично что он не выплевывает float из операции над int
И да, в JS как раз бы не было такой проблемы, там бы все норм поделилось
Нажмите, чтобы раскрыть...Не, сильная типизация это точно не про то, что A, A -> A. Это называется бинарная операция с внутренним законом композиции.
Вообще лучше не использовать выражения: "слабо типизированный язык", "сильно типизированный язык". Потому что консенсуса, нормального определения что это такое вообще, ты не особо найдёшь.
Lambda-chan сказал(а):↑Ну это так почти во всех языках работает, причем в независимости от типизации. Кроме хаскелля и паскаля, не вспомню примеров, где бы это работало по-другому.
Нажмите, чтобы раскрыть...Ну python, clojure (многие другие лиспы тоже), прологи. Где всякие // и quot для целочисленного подележа.
Kujivunia сказал(а):↑
dist = height / (plank * 2.0 - height) / Math.Cos(cam.fov * 0.5 - (bar * cam.fov /width));
dist = height / (plank * 2 - height) / Math.Cos(cam.fov / 2 - (bar * cam.fov / width));
Нажмите, чтобы раскрыть...Да напиши dist = height / (plank * 2d - height) / Math.Cos(cam.fov / 2d - (bar * cam.fov / width));
а cam.fov почему int? plank почему int? какой в этом смысл?Да и как сказали выше, в c# всё чётко, есть явное и не явное привидение. Либо корректно объявляешь типы, либо полагаешься на своё знание неявного привидение. Как ты понимаешь, название не просто так.
E1ektr0 сказал(а):↑Да напиши dist = height / (plank * 2d - height) / Math.Cos(cam.fov / 2d - (bar * cam.fov / width));
а cam.fov почему int? plank почему int? какой в этом смысл?Да и как сказали выше, в c# всё чётко, есть явное и не явное привидение. Либо корректно объявляешь типы, либо полагаешься на своё знание неявного привидение. Как ты понимаешь, название не просто так.Нажмите, чтобы раскрыть...Ничё не чётко, у него динамическая нестрогая типизация говна. В паскале всё чётко. В ассемблере всё чётко. А тут нет.
Насчёт типов.
dist - double
height - int
plank - int
2 - int (должен быть)
cam.fov - double (почему ты подумал что инт?)
bar - int
width - int
Ну, Math.Cos очевидно double возвращает ещё.
Ну т.е. моя логика:
double = height/(int) / double
double = int / int / double
Ну тут уже по левой части выражения, что не нужно ничего к инту приводить, я же в дабл считаю. Но нет, он решает привести. Понятия не имею в каком порядке он считает, у него слева дабл, справа дабл, а ответ он приводит к инту а потом обратно к даблу
Mask of Sadness сказал(а):↑Учи язык. Ради интереса открыл метанит, арифметические операторы и там про это написано. Хотя логика неочевидная, да
В Dart гораздо удобнее реализовано, есть оператор / который возвращает double и ~/ возвращает int.Нажмите, чтобы раскрыть...Kujivunia сказал(а):↑Вот щас бы перед использованием весьма определённого и простейшего оператора деления искать чё он там делает.
А давайте мы для каждого токена будем так делать?
Вдруг если перед { написать 2 пробела, то она скипается каждый чётный цикл, а если 3 пробела, то каждый нечётный цикл, а если 1 пробел, то цикл просто не выполняется?
А вдруг если мы складываем дабл с интом, то получаем в ответе округлённый вверх результат деления инта на дабл? А вдруг если мы пишем
int d; это значит, что мы сделали класс cPowCannon с полем double p = 8; и методом public static int qwe(Point d) => 5846;
Нажмите, чтобы раскрыть...
Ну, вроде, уже все сказали, что это норма для некоторых языков
int number = 5;
float floatNumber = number / 2; //ответ: 2 т.к. int / intЕсли ты делаешь такие операции, то надо ставить литералы(ещё называют суффиксами)
int number = 5;
float floatNumber = number / 2f; //ответ: 2.5F / f - float
M / m - decimal
D / d - double
L / l - long
Kujivunia сказал(а):↑a/b он тебе преобразует и в целочисленное деление, и в нормальное, причём ЧСХ вообще без предупреждения, ни тебе ошибки, ни тебе warning.
Нажмите, чтобы раскрыть...Купи себе Resharper(R#) для студии. Там есть проверка на "PossibleLossOfFraction" и тебе подсветит, где ты должен посмотреть.
С точки зрения спецификации C# и компилятора, эта валидная запись и все твои хотелки про предупреждения, то это надо обращаться ко всяким Roslyn анализаторам, PVS-studio, Resharper и так далее.
Kujivunia сказал(а):↑Я потратил три с половиной часа чтобы этот баг найти.
Нажмите, чтобы раскрыть...Как-то долго, такое обычным дебаггингом должно находиться быстро.
Когда делаешь такие вещи, лучше свою платформу изучить. Есть ещё такая штука как Floating Point Arithmetic и у .NET тоже будут свои заморочки
float x = 5.05f;
float y = 0.95f;
Console.WriteLine((x + y) == 6.0f); //Resharper тоже тебя предупредит
Ответ true или false будет зависить от рантайма, от битности программы и от железа.
В .NET 5, оба x86 и x64 дают true.
В .NET 4.7, x86 дает false, но на x64 будет true.
И т.д.
VovkaKalibrovka сказал(а):↑жаль что на любом сайте по Си Шарпу ясно написано, что если a,b целые (int) то результат будет целым (int) а если a или b float то ответ float
Нажмите, чтобы раскрыть...не проще все на флоатах делать, дабы не было косяка в любом случае?
я так на питоне делаю и не парюсь
Тема закрыта
-
ЗаголовокОтветов ПросмотровПоследнее сообщение
-
Сообщений:2
Просмотров:7
-
Сообщений:17
Просмотров:28
-
Сообщений:5
Просмотров:9
-
Сообщений:12
Просмотров:23
-
Сообщений:9
Просмотров:17


