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

ла я думалMath.Sign было бы правильным путем, но после запуска теста кажется, что он лечит-0.0 а также+0.0 тот же самый.

 adrianbanks19 янв. 2011 г., 20:45
 Darin Dimitrov19 янв. 2011 г., 20:37
Что такоеотрицательный ноль и чем он отличается отположительный ноль и чем он отличается отнуль? Математически они одинаковы.IEEE 754ically возможно, нет.
 Federico klez Culloca19 янв. 2011 г., 20:39
@ Darin Dimitrov, вы когда-нибудь посещали курс математического анализа? :П
 finnw19 янв. 2011 г., 20:46
Если вы говорите о двойниках IEEE,это хорошо определено.
 Darin Dimitrov19 янв. 2011 г., 20:40
@ Клез, да у меня есть. У меня даже есть степень по математике :-)

Ответы на вопрос(6)

    public static bool IsNegativeZero(double value) {
        if (value != 0) return false;
        int index = BitConverter.IsLittleEndian ? 7 : 0;
        return BitConverter.GetBytes(value)[index] == 0x80;
    }

Редактировать: как указано в ОП, это не работает в режиме выпуска. JIT-оптимизатор x86 серьезно относится к оператору if () и загружает ноль напрямую, а не загружаетстоимость, Который действительно более производительный. Но это приводит к тому, что отрицательный ноль теряется. Код должен быть де-настроен, чтобы предотвратить это:

    public static bool IsNegativeZero(double value) {
        int index = BitConverter.IsLittleEndian ? 7 : 0;
        if (BitConverter.GetBytes(value)[index] != 0x80) return false;
        return value == 0;
    }

Это довольно типичное поведение для x86 джиттера, кстати, оно не очень хорошо обрабатывает угловые случаи, когда оптимизирует код с плавающей запятой. Джиттер х64 намного лучше в этом отношении. Хотя, возможно, нет лучшего случая, чем придание значения отрицательному нулю. Будьте предупреждены.

 Hans Passant19 янв. 2011 г., 21:32
Я повторяю, оператор if сбивает с толку оптимизатор JIT. Теперь предполагается, что значение равно нулю, а не отрицательному нулю, и загружает его напрямую с помощью fldz, а не загрузкистоимость, Потому что это быстрее. Вы будете бороться с этим плохо и в своем собственном коде. Сообщение обновлено.
 ChaosPandion19 янв. 2011 г., 21:18
По какой-то причине, когда я собираю это с целью x86 с включенной оптимизацией и запускаю ее вне передачи Visual Studio-0.0 вернусьfalse, Ох, и это, кажется, средняя производительность мудрый.
 ChaosPandion19 янв. 2011 г., 22:15
К сожалению, чтобы полностью реализовать стандарт ECMAScript, я должен знать,-0.0.
 Hans Passant19 янв. 2011 г., 22:32
Я вижу, как стандарты сталкиваются в лоб. Удачи с этим.

В целом, вы можете сделать,

bool IsNegative(double value)
{
    const ulong SignBit = 0x8000000000000000;
    return ((ulong)BitConverter.DoubleToInt64Bits(value) & SignBit) == SignBit;
}

или, если хотите,

[StructLayout(LayoutKind.Explicit)]
private struct DoubleULong
{
    [FieldOffset(0)]
    public double Double;

    [FieldOffset(0)]
    public readonly ulong ULong;
}

bool IsNegative(double value)
{
    var du = new DoubleULong { Double = value };
    return ((du.ULong >> 62) & 2) == 2;
}

Последнее дает примерно 50% улучшения производительности при отладке, но. После компиляции в режиме релиза и запуска из командной строкинет существенной разницы.

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

x == 0 && 1 / x < 0
Решение Вопроса

private static readonly long NegativeZeroBits =
    BitConverter.DoubleToInt64Bits(-0.0);

public static bool IsNegativeZero(double x)
{
    return BitConverter.DoubleToInt64Bits(x) == NegativeZeroBits;
}

В основном это тестирование на точную битовую комбинацию -0.0, но без необходимости ее жесткого кодирования.

 ChaosPandion19 янв. 2011 г., 21:23
@leppie - Теперь это круто:return *(((long*) &value));
 Adrian Ratnapala18 февр. 2014 г., 05:53
Это не очень неприятно, потому что (а) он хорошо инкапсулирован и (б) если пользователь не может полагаться на IEEE с плавающей запятой, он не может полагаться на -0.0, даже если он существует. Лучшая абстракция была быbool IsNegative(double x){return BitConverter.DoubleToInt64Bits(x) < 0;}, Это функция, которая на самом деле должна быть в стандартеMath класс.
 ChaosPandion19 янв. 2011 г., 21:00
Кажется, ваше решение примерно в 25 раз быстрее моего.
 John19 янв. 2011 г., 23:44
Пришлось искать "гроти"
 leppie19 янв. 2011 г., 21:17
В качестве дополнительного бонуса, никаких дополнительных накладных расходов :) Вы должны любить силуunsafe код иногда :)

После небольшого поиска я наконец-то добрался доРаздел 7.7.2 спецификации C # и придумал это решение.

private static bool IsNegativeZero(double x)
{
    return x == 0.0 && double.IsNegativeInfinity(1.0 / x);
}
 Jon Skeet19 янв. 2011 г., 20:46
Хотя я приветствую изобретательность, я не уверен, что это самыйудобочитаемый подход :)
 Jon Skeet19 янв. 2011 г., 20:47
На самом деле, -1 - он думает, что -double.Epsilon также отрицательный ноль ...
 finnw19 янв. 2011 г., 20:55
@ Энтони Пеграм, не совсем. double.Epsilon денормализован, поэтому он меньше 2 ** (минимальный показатель степени). Не существует эквивалента денормализации для чрезвычайнобольшой значения, поэтому обратное слишком велико, чтобы быть представимым.
 ChaosPandion19 янв. 2011 г., 20:48
@Jon - Даг Наббит
 Anthony Pegram19 янв. 2011 г., 20:50
Любопытно, что 1 / double. Эпсилон оценил бы до бесконечности.

Вот еще один взлом. Это использует тот факт, чтоEquals наstruct будет делать побитовое сравнение вместо вызоваEquals на его членов:

struct Negative0
{
    double val;
    public static bool Equals(double d)
    {
        return new Negative0 { val = -0d }.Equals(new Negative0 { val = d });
    }
}

Negative0.Equals(0); // false
Negative0.Equals(-0.0); // true

 Vladimir Reshetnikov23 июл. 2013 г., 02:19
ValueType.Equals не всегда выполняет побитовое сравнение. И, к сожалению, точные условия, когда он решит это сделать, не документированы и могут варьироваться в зависимости от версии / платформы CLR.

Ваш ответ на вопрос