Преобразование задач из интервала для плавания

EHa делает две вещи. Прежде всего, он подавляет оптимизацию, которая исключает фильтры исключений, которые автоматически вызывают деструкторы локальных переменных класса, если анализатор кода не может увидеть какой-либо код, который может вызвать исключение C ++. Это делает разматывание стека безопасным для любого вида исключения, а не только для исключения C ++. Затраты на эти фильтры исключений составляют время на x86 и пространство на x86 и x64.

И да, он изменяет поведение catch (...), теперь он также фильтрует все исключения SEH, а не только C ++. Это действительно азартная игра, потому что вы ловите все очень неприятные вещи, асинхронные аппаратные исключения. Хотя я лично не думаю, что перехват всех исключений C ++ также очень оправдан, у вас все еще есть смутное представление о том, в какой степени изменилось состояние программы и почему это не удалось.

Реально, вам нужно переключиться на использование __try/__except, чтобы вы могли написать свой собственный фильтр исключений и избежать обнаружения плохих. Код исключения для исключений C ++ - 0xe04d5343 («MSC»). Использование _set_se_translator () было бы другим подходом.

13
задан mskfisher 9 May 2012 в 19:56
поделиться

6 ответов

Я посмотрел, был ли это компилятор, выполняющий математические вычисления, но он ведет себя таким образом, даже если вы его отключите:

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) для обоих.

11
ответ дан 2 December 2019 в 00:03
поделиться

Ответ Марка правильный в том смысле, что это преобразование между nativefloat и float32 / float64.

Это описано в спецификации CLR ECMA, но Дэвид Нотарио объясняет это намного лучше, чем я.

2
ответ дан 2 December 2019 в 00:03
поделиться

этот код ...

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 -> компилятор выполнил вычисление .. В противном случае возникает проблема преобразования десятичных чисел в двоичные

2
ответ дан 2 December 2019 в 00:03
поделиться

Попробуйте преобразовать float в double во втором примере:

double flo = 195.95F * 100;
int num = (int) flo;

Я предполагаю, что в вашем первом примере компилятор использует double для хранения промежуточного результата, поэтому в случае с плавающей точкой вы ' повторная потеря точности.

1
ответ дан 2 December 2019 в 00:03
поделиться

Когда вы умножаете на 100, это целое число, поэтому на этом этапе выполняется неявное преобразование. Если вы поставите «F» после 100, готов поспорить, они будут такими же.

Я обычно использую бокс / распаковку в круглых скобках, когда это ссылочный тип. Когда это тип значения, я стараюсь использовать статические методы Convert.

Попробуйте Convert.ToSingle (YourNumber); для более надежного преобразования.

HTH

0
ответ дан 2 December 2019 в 00:03
поделиться

Я не могу ответить, почему второй работает, а первый нет. Тем не менее, я могу сказать вам, что 195.95 - это десятичное число без завершения в двоичном формате, и поэтому ошибки округления, подобные этой, неизбежны.

Попробуйте преобразовать в double, а не в float. Вы также можете использовать денежный или десятичный тип вместо числа с плавающей запятой. Это сохранит число по-другому и более точно.

Для получения дополнительной информации о числах с плавающей запятой и представлении IEEE перейдите сюда:

http://en.wikipedia.org/wiki/IEEE_754

0
ответ дан 2 December 2019 в 00:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: