LINUX.ORG.RU

Знак переменной

 , ,


0

2

Есть ли кроссплатформенный способ определить знак переменной, лучше этого:

T val = get_random(-max, max);
T sign = (val > 0) - (val < 0);

★★★★★

Последнее исправление: andreyu (всего исправлений: 1)
Ответ на: комментарий от emulek

кстати, само значение false не определено, но определено, что при конвертации в число оно становится нулём. Как и NULL.

Т.е. если сделать union, то можно обнаружить, что ВНЕЗАПНО false == 18, однако если скастовать его в int, оно станет нулём.

А вот true становится единицей. Вроде уже в C89 есть этот пункт, если я ничего не путаю.

emulek
()
Ответ на: комментарий от emulek

Интересно: в stdbool.h тип bool организован как битовое поле? А то я вообще не врубаюсь, как можно сделать переменную, в которую что ни пиши (кроме 0), прочтешь 1 (0).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Кто бы говорил! Сам-то пихаешь fabs!

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

Разве не видно, что я х-ню там написал? ☺

emulek
()
Ответ на: комментарий от emulek

само значение false не определено

Помнишь прикол с

#define FALSE 1
#define TRUE 0

int x = TRUE;
...
?

Если явно сравнивать, то даже работать будет, но стоит где-нибудь написать if(x)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

обычно bool == int. Он так и проверяется:

bool flag;
…
if(flag)
  …;

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

Мне лень, сам попробуй такой код:

int main(int argc, const char* argv[])
{
  bool b = argc&2;
  return argc + b;
}

обычно разницы bool/int не существует. Только в касте меняется на

int bool2int(bool b)
{
  return b? 1: 0;
}

emulek
()
Ответ на: комментарий от emulek

Вот как они это сделали?

cat 1.c 
#include <stdio.h>

typedef enum{
  false = 0,
  true  = 1
} bool;

int main(){
  int i;
  bool x;
  _Bool y;
  for(i = -5; i < 6; i++){
    x = i;
    y = i;
    printf("i = %d, bool(i) = %d, _Bool(i) = %d\n", i, x, y);
  }
  return 0;
}

gcc 1.c && ./a.out 
i = -5, bool(i) = -5, _Bool(i) = 1
i = -4, bool(i) = -4, _Bool(i) = 1
i = -3, bool(i) = -3, _Bool(i) = 1
i = -2, bool(i) = -2, _Bool(i) = 1
i = -1, bool(i) = -1, _Bool(i) = 1
i = 0, bool(i) = 0, _Bool(i) = 0
i = 1, bool(i) = 1, _Bool(i) = 1
i = 2, bool(i) = 2, _Bool(i) = 1
i = 3, bool(i) = 3, _Bool(i) = 1
i = 4, bool(i) = 4, _Bool(i) = 1
i = 5, bool(i) = 5, _Bool(i) = 1

Явно же не через enum.

Или _Bool специально обрабатывается компилятором?

Eddy_Em ☆☆☆☆☆
()
#include <type_traits>
#include <iostream>

template <typename T>
bool is_negative(T number) noexcept {
    return ! (std::is_unsigned<T>::value || number >= 0);
}

int main() {
    long long signed_pos_1 = 45;
    long long signed_neg_1 = -45;
    long long signed_zero_1 = 0;
    double signed_pos_2 = 45.0;
    double signed_neg_2 = -45.0;
    double signed_zero_2 = 0.0;
    unsigned long unsigned_pos_1 = 45;
    unsigned long unsigned_zero_1 = 0;

    std::cout << is_negative(signed_pos_1);
    std::cout << is_negative(signed_zero_1);
    std::cout << is_negative(signed_pos_2);
    std::cout << is_negative(signed_zero_2);
    std::cout << is_negative(unsigned_pos_1);
    std::cout << is_negative(unsigned_zero_1);

    std::cout << is_negative(signed_neg_1);
    std::cout << is_negative(signed_neg_2);
}
hlebushek ★★
()
Ответ на: комментарий от hlebushek

Ну и если нужно прямо знак с учетом нуля:

template <typename T, typename Result>
constexpr Result sign_of_number(T number) noexcept {
    static_assert(
        std::is_signed<Result>::value,
        "sign_of_number can only return result of signed type"
    );
    if (number == 0) {
        return 0;
    }
    else if (is_negative(number)) {
        return -1;
    }
    return 1;
}

А еще наверное обе эти функции можно сделать constexpr.

hlebushek ★★
()
Ответ на: комментарий от MyTrooName

откровенно говоря, хочется отдельно на каждый коммент ответить таким же сообщением

MyTrooName ★★★★★
()
Ответ на: комментарий от emulek

Вона как, оказывается!

Но таки действительно получается, что gcc специальным образом обрабатывает _Bool (точно так же, как специально обрабатываются, скажем, uint8_t или uint64_t).

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

ну я может путаю, но в старых стандартах «true» могло превратится во что угодно, например 5<2→3, т.е. компилятор просто вычитал 5-2, почему я и рекомендую if. Дело в том, что из

if(x<y)
компилятор сделает более быстрый код, чем из
bool b = x<y;
…
if(b)
компилятору придётся следовать стандарту, и преобразовывать x-y в 0 или 1. В первом случае компилятор просто выполнит вычитание.

Совсем уныло, если на целевой платформе нет SETNZ или чего-то подобного.

ЗЫЖ общее правило: преждевременная оптимизация — всегда зло. ©Кнут.

Ну я-бы частное предложил: не нужно считать себя умнее компилятора, платформы разные бывают, и задрачивать под каждую платформу должен компилятор, а не программист.

точно так же, как специально обрабатываются, скажем, uint8_t или uint64_t

угу. Типы char, short, int, long придумали специально, что-бы они «росли» вместе с «ростом компьютера».

emulek
()
Ответ на: комментарий от hlebushek

А еще наверное обе эти функции можно сделать constexpr.

Нельзя, если number - не на этапе компиляции вычисляется. Можно максимум сделать inline и поглядеть на ассемблерный выхлоп, после чего помедитировать, возможно оно сведётся к выводу идентичному указанному ТС выражению.

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

Подписался на тред чё.

pon4ik ★★★★★
()
Ответ на: комментарий от Deleted

Кстати, если требуется для флоатов корректно обрабатывать NaN, то код ошибочный.

Ну на nan можно проверить условием (val != val) - значит nan. Но мне проверка на nan ненужна.

andreyu ★★★★★
() автор топика
Ответ на: комментарий от hlebushek

На выходе bool, а нужно -1, 0, 1.

andreyu ★★★★★
() автор топика
Ответ на: комментарий от andreyu

В моем случае float, но хотелось бы универсального решения. Платформо-зависимая магия не подходит.

А что, на разных платформах разный IEEE 754? Бери верхний бит и готово.

mix_mix ★★★★★
()
Ответ на: комментарий от hlebushek

Код раздут, ветвления. Constexpr там откуда?

andreyu ★★★★★
() автор топика
Ответ на: комментарий от mix_mix

А что, на разных платформах разный IEEE 754? Бери верхний бит и готово.

Была такая мысль, но это пахнет костылем. А костыль делать не хочется.

andreyu ★★★★★
() автор топика
Ответ на: комментарий от andreyu

Кистати да, напиши функу, на 99% платформ она будет дешоовая, а под остальные дифайн на любой костыль с коментом ССЗБ :)

pon4ik ★★★★★
()
Ответ на: комментарий от andreyu

На nan можно std::numeric_limmits заюзать. На этом этапе как будет и constexpr выражения заюзать, дабы лишняя проверка когда не нужно не мешалась.

pon4ik ★★★★★
()
Ответ на: комментарий от andreyu

Была такая мысль, но это пахнет костылем. А костыль делать не хочется.

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

mix_mix ★★★★★
()
Ответ на: комментарий от hlebushek

Ну и если нужно прямо знак с учетом нуля:

то придётся делать ещё и с учётом его знака и неозвученных хотелок ТС по его имплементации :-) а есть ещё epsilon и вопрос учитывать ли его при сравнении с 0. есть два inf`а со знаками.

MKuznetsov ★★★★★
()
Ответ на: комментарий от invy

Какие приследуешь цели? Так ли принципиально отделять 0?

Да, нужно узнать есть ли отклонение движения объекта от прямой.

andreyu ★★★★★
() автор топика
Ответ на: комментарий от andreyu

Была такая мысль, но это пахнет костылем. А костыль делать не хочется.

Можно подумать типичный код на С не набор платформозависимых костылей.

anonymous
()
Ответ на: комментарий от invy

Учти что если у тебя float то строго нуля у тебя тоже не будет.

Если туда записали ноль, то будет:

float val = 0.0f;
if(val == 0.0f)
{
   printf("0.0f\n");
}
andreyu ★★★★★
() автор топика
Ответ на: комментарий от andreyu

Ну на nan можно проверить условием (val != val)

нельзя. Ибо это UB вообще-то. В IEEE754 это может дать как «результат» NaN, так и исключение.

emulek
()
Ответ на: комментарий от andreyu

Если туда записали ноль

это исключительная ситуация. Кстати, а как по твоему -0 == +0 ы?

emulek
()
Ответ на: комментарий от andreyu

Ну ты же это значение считаешь. Не вижу смысла отдельно выделять ноль. Знак для направления отклонкеия и по модулю значение < epsilon должно хватить целей.

invy ★★★★★
()

Воистину на Фортране можно писать на любом языке!

buddhist ★★★★★
()

лучше

По какой метрике?

buddhist ★★★★★
()

Сравнить число и abs(число) ?

Pinkbyte ★★★★★
()
Ответ на: комментарий от Deleted

Чуваку как я понял нужно 3 варианта: -,+ и 0. Как ты понимаешь это немного другое условие.

abs(число) = число - число неотрицательное(>=0)
abs(число) != число - соответственно отрицательное(<0)

Тут без отдельной проверки на 0 не вычленить.

Pinkbyte ★★★★★
()
Ответ на: комментарий от Pinkbyte

Ой, пардон, я не так тебя понял с самого начала.

Deleted
()
Ответ на: комментарий от invy

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

anonymous
()
Ответ на: комментарий от anonymous

В качестве иллюстрации можно взглянуть на движение по закону

x(t)=sin(t*A)/A

При значениях A достаточно больших направление отклонения от нуля в один и тот же момент времени t будет сильно зависеть от выбранной величины dt.

anonymous
()
Ответ на: комментарий от anonymous

Вообще это очень здравая мысль насчет малого эпсилон.

В общем случае этот так. В моем случае есть строго или 0, или некое отклонение. Исходя из этого мне нужен результат 0, -1, 1.

andreyu ★★★★★
() автор топика
29 марта 2015 г.
Ответ на: комментарий от Eddy_Em

В Форте приколы ещё интереснее. Там можно 2 определить как 3 и дважды два отныне становится равным девяти. Можно и умножение переопределить во что угодно, не рожая никаких классов...

hobbit ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.