Значения плавающие, ведущие себя по-другому через сборки выпуска и отладки

Сначала вам понадобятся несколько кортежей:

,
public class Tuple2<S, T> {
    public final S first;
    public final T second;

    public Tuple2(S first, T second) {
        this.first = first;
        this.second = second;
    }
}
,

,

,
public class Tuple3<S, T, U> {
    public final S first;
    public final T second;
    public final U third;

    public Tuple3(S first, T second, U third) {
        this.first = first;
        this.second = second;
        this.third = third;
    }
}
,

,

,
public class Tuple4<S, T, U, V> {
    public final S first;
    public final T second;
    public final U third;
    public final V fourth;

    public Tuple4(S first, T second, U third, V fourth) {
        this.first = first;
        this.second = second;
        this.third = third;
        this.fourth = fourth;
    }
}
,

. Когда у вас есть свои кортежи, вы можете написать вспомогательные функции, которые работа, похожая на Transformations.map, но теперь вы можете сделать:

public class LiveDataTransformations {
    private LiveDataTransformations() {}

    public static <S, T> LiveData<Tuple2<S,T>> ifNotNull(LiveData<S> first, LiveData<T> second) {
        MediatorLiveData<Tuple2<S, T>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            if(_first != null && _second != null) {
                mediator.setValue(new Tuple2(_first, _second));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            if(_first != null && _second != null) {
                mediator.setValue(new Tuple2(_first, _second));
            }
        });

        return mediator;
    }

    public static <S, T, U> LiveData<Tuple3<S,T,U>> ifNotNull(LiveData<S> first, LiveData<T> second, LiveData<U> third) {
        MediatorLiveData<Tuple3<S, T, U>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        mediator.addSource(third, (_third) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            if(_first != null && _second != null && _third != null) {
                mediator.setValue(new Tuple3(_first, _second, _third));
            }
        });

        return mediator;
    }

    public static <S, T, U, V> LiveData<Tuple4<S,T,U, V>> ifNotNull(LiveData<S> first, LiveData<T> second, LiveData<U> third, LiveData<V> fourth) {
        MediatorLiveData<Tuple4<S, T, U, V>> mediator = new MediatorLiveData<>();

        mediator.addSource(first, (_first) -> {
            T _second = second.getValue();
            U _third = third.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(second, (_second) -> {
            S _first = first.getValue();
            U _third = third.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(third, (_third) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            V _fourth = fourth.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        mediator.addSource(fourth, (_fourth) -> {
            S _first = first.getValue();
            T _second = second.getValue();
            U _third = third.getValue();
            if(_first != null && _second != null && _third != null && _fourth != null) {
                mediator.setValue(new Tuple4(_first, _second, _third, _fourth));
            }
        });

        return mediator;
    }
}

Теперь вы можете сделать

LiveData<???> liveDataForView;

private void setupForView() {
   LiveData<Tuple3<Foo, Bar, FooBar>> intermediate =  LiveDataTransformations.ifNotNull(liveData1, liveData2, liveData3);
   liveDataForView = Transformations.map(intermediate, (tuple) -> {
       Foo foo = tuple.first;
       Bar bar = tuple.second;
       FooBar fooBar = tuple.third;

       return /*Some combinations of the LiveDatas*/
   });
}
7
задан Coding Mash 7 September 2012 в 16:40
поделиться

9 ответов

Режим выпуска может иметь другой набор стратегии FP. Существуют различные арифметические режимы с плавающей точкой в зависимости от уровня оптимизации, которую Вы хотели бы. MSVC, например, имеет строгий, быстро, и точные режимы.

11
ответ дан 6 December 2019 в 07:53
поделиться

Я знаю, что на ПК, регистры с плавающей точкой 80 битов шириной. Таким образом, если вычисление сделано полностью в FPU, Вы извлекаете пользу 80 битов точности. С другой стороны, если промежуточный результат выселен в нормальный регистр и назад, это становится усеченным к 32 битам, который дает различные результаты.

Теперь полагайте, что сборка конечных версий будет иметь оптимизации, которые сохраняют промежуточные результаты в регистрах FPU, тогда как отладочная сборка, вероятно, наивно скопирует промежуточные результаты назад и передаст между памятью и регистрами - и там у Вас есть свое различие в поведении.

Я не знаю, происходит ли это на X360 также или нет.

4
ответ дан 6 December 2019 в 07:53
поделиться

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

Смотрите на/fp (Укажите Поведение С плавающей точкой).

3
ответ дан 6 December 2019 в 07:53
поделиться

В дополнение к различным режимам с плавающей точкой другие указали, SSE или подобная векторная оптимизация могут быть включены для выпуска. Преобразование арифметики с плавающей точкой от стандартных регистров до векторных регистров может иметь эффект на более низкие биты Ваших результатов, поскольку векторные регистры обычно будут более узкими (меньше битов), чем стандартные регистры с плавающей точкой.

2
ответ дан 6 December 2019 в 07:53
поделиться

Это несоответствие может быть вызвано компиляторной оптимизацией, которая обычно делается в режиме выпуска, но не в режиме отладки. Например, компилятор может переупорядочить некоторые операции для ускорения выполнения, которое может очевидно вызвать незначительные различия в результате с плавающей точкой.

Так, я сказал бы, скорее всего, что это не ошибка. Если Вы действительно волнуетесь по поводу этого, попытайтесь включить оптимизацию в Режиме отладки.

0
ответ дан 6 December 2019 в 07:53
поделиться

Не ошибка. Этот тип различия должен ожидаться.

Например, некоторые платформы имеют регистры плавающие, которые используют больше битов, чем хранится в памяти, так хранение значения в регистре может привести к немного отличающемуся результату по сравнению с хранением к памяти и перезагрузкой из памяти.

1
ответ дан 6 December 2019 в 07:53
поделиться

Это не ошибка. Любая плавающая точка uperation имеет определенную неточность. В режиме Release оптимизация изменит порядок операций, и Вы получите немного отличающийся результат. Разница должна быть небольшой, все же. Если это является большим, у Вас могли бы быть другие проблемы.

2
ответ дан 6 December 2019 в 07:53
поделиться

При установке переключателя компилятора, который позволил компилятору переупорядочивать операции с плавающей точкой, - например,/fp:fast - затем, очевидно, это не ошибка.

Если Вы не установили никакой подобный переключатель, то это - ошибка - C и стандарты C++ не позволяют компиляторам переупорядочивать операции без Вашего разрешения.

0
ответ дан 6 December 2019 в 07:53
поделиться

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

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

0
ответ дан 6 December 2019 в 07:53
поделиться
Другие вопросы по тегам:

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