EHa делает две вещи. Прежде всего, он подавляет оптимизацию, которая исключает фильтры исключений, которые автоматически вызывают деструкторы локальных переменных класса, если анализатор кода не может увидеть какой-либо код, который может вызвать исключение C ++. Это делает разматывание стека безопасным для любого вида исключения, а не только для исключения C ++. Затраты на эти фильтры исключений составляют время на x86 и пространство на x86 и x64.
И да, он изменяет поведение catch (...), теперь он также фильтрует все исключения SEH, а не только C ++. Это действительно азартная игра, потому что вы ловите все очень неприятные вещи, асинхронные аппаратные исключения. Хотя я лично не думаю, что перехват всех исключений C ++ также очень оправдан, у вас все еще есть смутное представление о том, в какой степени изменилось состояние программы и почему это не удалось.
Реально, вам нужно переключиться на использование __try/__except
, чтобы вы могли написать свой собственный фильтр исключений и избежать обнаружения плохих. Код исключения для исключений C ++ - 0xe04d5343 («MSC»). Использование _set_se_translator () было бы другим подходом.
Я посмотрел, был ли это компилятор, выполняющий математические вычисления, но он ведет себя таким образом, даже если вы его отключите:
static void Main()
{
int i = (int)(GetF() * GetI()); // 19594
float f = GetF() * GetI();
int j = (int)f; // 19595
}
[MethodImpl(MethodImplOptions.NoInlining)]
static int GetI() { return 100; }
[MethodImpl(MethodImplOptions.NoInlining)]
static float GetF() { return 195.95F; }
Похоже, разница в том, остается ли он в регистрах (шире, чем у обычного r4) или принудительно использует переменную float
:
L_0001: call float32 Program::GetF()
L_0006: call int32 Program::GetI()
L_000b: conv.r4
L_000c: mul
L_000d: conv.i4
L_000e: stloc.0
vs
L_000f: call float32 Program::GetF()
L_0014: call int32 Program::GetI()
L_0019: conv.r4
L_001a: mul
L_001b: stloc.1
L_001c: ldloc.1
L_001d: conv.i4
L_001e: stloc.2
Единственное отличие - stloc.1
/ ldloc.1
].
Это подтверждается тем фактом, что если вы выполните оптимизированную сборку (которая удалит локальную переменную), я получу один и тот же ответ (19594) для обоих.
Ответ Марка правильный в том смысле, что это преобразование между nativefloat и float32 / float64.
Это описано в спецификации CLR ECMA, но Дэвид Нотарио объясняет это намного лучше, чем я.
этот код ...
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
float result = 195.95F*100;
int intresult = (int)(195.95F * 100);
}
}
}
дать этому IL
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 14 (0xe)
.maxstack 1
.locals init ([0] float32 result,
[1] int32 intresult)
IL_0000: nop
IL_0001: ldc.r4 19595.
IL_0006: stloc.0
IL_0007: ldc.i4 0x4c8a
IL_000c: stloc.1
IL_000d: ret
} // end of method Program::Main
посмотреть на IL_00001 -> компилятор выполнил вычисление .. В противном случае возникает проблема преобразования десятичных чисел в двоичные
Попробуйте преобразовать float в double во втором примере:
double flo = 195.95F * 100;
int num = (int) flo;
Я предполагаю, что в вашем первом примере компилятор использует double для хранения промежуточного результата, поэтому в случае с плавающей точкой вы ' повторная потеря точности.
Когда вы умножаете на 100, это целое число, поэтому на этом этапе выполняется неявное преобразование. Если вы поставите «F» после 100, готов поспорить, они будут такими же.
Я обычно использую бокс / распаковку в круглых скобках, когда это ссылочный тип. Когда это тип значения, я стараюсь использовать статические методы Convert.
Попробуйте Convert.ToSingle (YourNumber); для более надежного преобразования.
HTH
Я не могу ответить, почему второй работает, а первый нет. Тем не менее, я могу сказать вам, что 195.95 - это десятичное число без завершения в двоичном формате, и поэтому ошибки округления, подобные этой, неизбежны.
Попробуйте преобразовать в double, а не в float. Вы также можете использовать денежный или десятичный тип вместо числа с плавающей запятой. Это сохранит число по-другому и более точно.
Для получения дополнительной информации о числах с плавающей запятой и представлении IEEE перейдите сюда: