C / C ++ 'da standart işaret fonksiyonu (signum, sgn) var mı?


409

Negatif sayılar için -1 ve pozitif sayılar için +1 döndüren bir işlev istiyorum. http://en.wikipedia.org/wiki/Sign_function Kendi yazmak için yeterince kolay, ama bir yerde standart bir kütüphanede olması gereken bir şey gibi görünüyor.

Edit: Özellikle, ben yüzer üzerinde çalışan bir işlev arıyordu.


13
0'a ne dönmeli?
Craig McQueen

61
@Craig McQueen; bu, pozitif sıfır veya negatif sıfır olmasına bağlıdır.
ysth

1
Dönüş değerini bir tamsayı olarak belirttiğinizi fark ettim. Tamsayı veya kayan nokta sayısı alan bir çözüm mü arıyorsunuz?
Mark Byers

6
@ysth @Craig McQueen, şamandıralar için de yanlış, değil mi? sgn (x) 'in tanımlaması eğer 0 döndürür diyor x==0. IEEE 754'e göre , negatif sıfır ve pozitif sıfır eşit olarak karşılaştırılmalıdır.
RJFalconer

5
@ysth "pozitif sıfıra veya negatif sıfıra bağlıdır". Aslında öyle değil.
RJFalconer

Yanıtlar:


506

Hiç kimse henüz güvenli bir C ++ sürümü yayınlamadı:

template <typename T> int sgn(T val) {
    return (T(0) < val) - (val < T(0));
}

Yararları:

  • Aslında signum (-1, 0 veya 1) uygular. Burada copysign kullanan uygulamalar yalnızca -1 veya 1 değerini döndürür. Ayrıca, buradaki bazı uygulamalar savurgan görünen bir int yerine bir şamandıra (veya T) döndürüyor.
  • Ints, float, double, unsigned shorts veya 0 tamsayı ile oluşturulabilen ve düzenlenebilir herhangi bir özel tip için çalışır.
  • Hızlı! copysignözellikle tanıtmanız ve ardından tekrar daralmanız gerekiyorsa yavaştır. Bu dalsızdır ve mükemmel bir şekilde optimize eder
  • Standartlar uyumlu! Bitshift hack düzgün, ancak sadece bazı bit gösterimleri için çalışır ve işaretsiz bir türünüz olduğunda çalışmaz. Uygun olduğunda manuel uzmanlaşma olarak sağlanabilir.
  • Doğru! Sıfırla yapılan basit karşılaştırmalar, makinenin dahili yüksek hassasiyetli sunumunu koruyabilir (örneğin, x87'de 80 bit) ve sıfıra erken yuvarlanmayı önleyebilir.

Uyarılar:

  • Bu bir şablondur, bu nedenle bazı durumlarda derlenmesi daha uzun sürebilir.
  • Görünüşe göre bazı insanlar, gerçekten imza uygulamayan yeni, biraz ezoterik ve çok yavaş bir standart kütüphane işlevinin kullanılmasının daha anlaşılır olduğunu düşünüyor.
  • < 0Çek parçası GCC en tetikler -Wtype-limitsişaretsiz türü için örneği oluşturulan uyarı. Bazı aşırı yükleri kullanarak bunu önleyebilirsiniz:

    template <typename T> inline constexpr
    int signum(T x, std::false_type is_signed) {
        return T(0) < x;
    }
    
    template <typename T> inline constexpr
    int signum(T x, std::true_type is_signed) {
        return (T(0) < x) - (x < T(0));
    }
    
    template <typename T> inline constexpr
    int signum(T x) {
        return signum(x, std::is_signed<T>());
    }

    (Bu ilk uyarı için iyi bir örnektir.)


18
@GMan: GCC sadece şimdi (4.5) şablon işlevleri için örnek sayısı için ikinci dereceden maliyete sahip olmayı bıraktı ve ayrıştırmak ve örneklemek için elle yazılmış işlevlerden veya standart C ön işlemcisinden çok daha pahalı. Bağlayıcı ayrıca yinelenen örneklemeleri kaldırmak için daha fazla iş yapmak zorundadır. Şablonlar ayrıca, # hesaplama içerir # içerir, bu da bağımlılık hesaplamasının daha fazla dosyanın yeniden derlenmesini zorlamak için daha uzun ve küçük (genellikle arabirim değil uygulama) değişikliklerini gerçekleştirmesini sağlar.

15
@Joe: Evet ve hala göze çarpan bir maliyet yok. C ++ şablonları kullanır, bu hepimizin anlaması, kabul etmesi ve aşması gereken bir şeydir.
GManNickG

42
Bekle, bu "copysign yavaş" iş nedir? Mevcut derleyicileri (g ++ 4.6+, clang ++ 3.0) kullanmak benim için mükemmel bir kodla std::copysignsonuçlanıyor gibi görünüyor : 4 talimat (satır içi), dallanma yok, tamamen FPU kullanılıyor. Bu cevapta verilen tarif, aksine, çok daha kötü kod üretir (çarpma, tamsayı birimi ve FPU arasında ileri geri hareket etme gibi birçok talimat) ...
snogglethorpe

14
@snogglethorpe: Bir copysignint çağırıyorsanız , float / double yapmayı teşvik eder ve dönüşte tekrar daralması gerekir. Derleyiciniz bu promosyonu optimize edebilir, ancak standart tarafından garanti edildiğini gösteren hiçbir şey bulamıyorum. Ayrıca copysign yoluyla oturum açmak için 0 vakasını elle işlemeniz gerekir - lütfen bunu herhangi bir performans karşılaştırmasına dahil ettiğinizden emin olun.

53
İlk sürüm dalsız değildir. İnsanlar neden bir ifadede kullanılan bir karşılaştırmanın dal üretmeyeceğini düşünüyor? Çoğu mimaride olacak. Yalnızca cmove (veya tahmin) olan işlemciler dalsız kod oluştururlar, ancak bunu üçlüler için veya bir kazanç ise / else yaparlar.
Patrick Schlüter

271

Bunun için standart bir işlev bilmiyorum. İşte yazmanın ilginç bir yolu:

(x > 0) - (x < 0)

İşte bunu yapmak için daha okunabilir bir yol:

if (x > 0) return 1;
if (x < 0) return -1;
return 0;

Üçlü operatörden hoşlanıyorsanız bunu yapabilirsiniz:

(x > 0) ? 1 : ((x < 0) ? -1 : 0)

7
Mark Ransom, ifadeleriniz için yanlış sonuçlar veriyor x==0.
avakar

3
@Svante: "Operatörlerin her biri <, >... belirtilen ilişki doğruysa 1, yanlışsa 0 verir"
Stephen Canon

11
@Svante: tam olarak değil. Değeri 0"false"; diğer herhangi bir değer "true" dur; ancak ilişkisel ve eşitlik operatörleri her zaman geri döner 0veya 1(bkz. Standart 6.5.8 ve 6.5.9). - ifadenin a * (x == 42)değeri ya 0yadır a.
pmg

21
Yüksek Performanslı Marka, C ++ etiketini kaçırdığınıza şaşırdım. Bu cevap çok geçerli ve bir aşağı oyu hak etmiyor. Dahası, elimde olsa bile copysignintegral için kullanmazdım x.
avakar

6
Herkes gerçek bir platformda hangi kod GCC / G ++ / başka bir derleyici yayar kontrol etti mi? Tahminimce "dalsız" versiyon bir yerine iki dal kullanıyor. Bitshifting muhtemelen çok daha hızlı ve performans açısından daha taşınabilir.
Jørgen Fogh

192

Bir argümandan işareti ve diğerinden mutlak değeri alan copysign () adında bir C99 matematik kütüphanesi işlevi vardır:

result = copysign(1.0, value) // double
result = copysignf(1.0, value) // float
result = copysignl(1.0, value) // long double

değerin işaretine bağlı olarak +/- 1,0 sonucunu verecektir. Kayan nokta sıfırlarının imzalandığını unutmayın: (+0) +1 ve (-0) -1 verir.


57
Bunu onayladı, en popüler yanıtı reddetti. SO topluluğunun standart bir kütüphane işlevini kullanmak için bir kesmek tercih ettiği görülüyor. Programlama tanrıları hepinizi dil standartlarına aşina olmayan akıllı programcılar tarafından kullanılan saldırıları deşifre etmeye mahk Maym etsin. Evet, bunun bana SO'ya bir ton temsilcisi mal olacağını biliyorum, ama geri kalanınızdan daha fazla comingtorm ile yan yana olmayı tercih ederim ...
Yüksek Performanslı Mark

34
Bu yakın, ancak sıfır için yanlış cevap veriyor (en azından sorudaki Wikipedia makalesine göre). Güzel öneri olsa. Yine de +1.
Mark Byers

4
Bir tamsayı istiyorsanız veya sıfırlar için tam imza sonucunu istiyorsanız, Mark Byers'ın cevabını seviyorum, ki bu son derece zarif! Yukarıdakileri umursamıyorsanız, copysign () uygulamasına bağlı olarak bir performans avantajı olabilir - kritik bir döngüyü optimize ediyor olsaydım, her ikisini de denerdim.
comingstorm

10
1) C99 her yerde tam olarak desteklenmez (VC ++ düşünün); 2) Bu aynı zamanda bir C ++ sorusudur. Bu iyi bir cevaptır, ancak yukarıdakiler de işe yarar ve daha yaygın olarak uygulanabilir.
Pavel Minaev

5
Kurtarıcı! -0,0 ile 0.0 belirlemek için bir yol gerekli
Ólafur Waage

79

Görünüşe göre cevapların çoğu orijinal soruyu kaçırdı.

C / C ++ 'da standart işaret fonksiyonu (signum, sgn) var mı?

Standart kütüphanede değil, ancak copysignneredeyse aynı şekilde kullanılabilen copysign(1.0, arg)var boostve standartın bir parçası olabilecek gerçek bir işaret fonksiyonu var .

    #include <boost/math/special_functions/sign.hpp>

    //Returns 1 if x > 0, -1 if x < 0, and 0 if x is zero.
    template <class T>
    inline int sign (const T& z);

http://www.boost.org/doc/libs/1_47_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/sign_functions.html


5
Bu, soruya sorulan sorulara mümkün olan en yakın çözümü sağladığı için en çok oy alan cevap olmalıdır.
BartoszKP

Son birkaç dakikadır neden standart kütüphanenin işaret fonksiyonuna sahip olmadığını merak ediyorum. Bu çok yaygındır - cmath başlığında bulunan gama işlevinden kesinlikle daha yaygın olarak kullanılır.
Taozi

4
Benzer sorular için sıklıkla aldığım açıklama "kendinizi uygulamak için yeterince kolay" dır Hangi IMO iyi bir neden değildir. Standardizasyonun, açık olmayan uç durumların ve bu kadar yaygın olarak kullanılan bir aracın nereye konulacağı sorunlarına tamamen inanmaktadır.
Catskul

77

Görünüşe göre, orijinal posterin sorusunun cevabı hayır. Hiçbir yoktur standart C ++ sgnişlevi.


2
@SR_ Doğru değilsiniz. copysign()ikincisi 0.0 ise ilk parametrenizi 0.0 yapmaz. Başka bir deyişle, John doğrudur.
Alexis Wilke

30

C / C ++ 'da standart işaret fonksiyonu (signum, sgn) var mı?

Evet, tanıma bağlı.

C99 ve sonraki sürümlerde signbit()makro<math.h>

int signbit(gerçek yüzen x); Makro döner onun argümanı değerinin işareti negatiftir ancak ve ancak sıfır olmayan bir değer. C11 §7.12.3.6
signbit


Yine de OP biraz farklı bir şey istiyor.

Negatif sayılar için -1 ve pozitif sayılar için +1 döndüren bir işlev istiyorum. ... şamandıralar üzerinde çalışan bir işlev.

#define signbit_p1_or_n1(x)  ((signbit(x) ?  -1 : 1)

Daha derine:

Aşağıdaki durumlarda gönderi belirli değildir: x = 0.0, -0.0, +NaN, -NaN .

Klasik bir signum()döner +1üzerine x>0, -1üzerinde x<0ve 0üstündex==0 .

Birçok cevap zaten bunu kapsıyor, ancak ele almıyor x = -0.0, +NaN, -NaN. Birçoğu, genellikle Sayı Değil ( NaN ) ve -0.0 içermeyen bir tam sayı bakış açısı için tasarlanmıştır. .

Tipik cevaplar signnum_typical() Açık gibi çalışır -0.0, +NaN, -NaN, geri döner 0.0, 0.0, 0.0.

int signnum_typical(double x) {
  if (x > 0.0) return 1;
  if (x < 0.0) return -1;
  return 0;
}

Bunun yerine, bu işlevi öneriyorum: Açık -0.0, +NaN, -NaN, geri döner -0.0, +NaN, -NaN.

double signnum_c(double x) {
  if (x > 0.0) return 1.0;
  if (x < 0.0) return -1.0;
  return x;
}

1
Ah, tam olarak peşindeyim. Bu Pharo Smalltalk github.com/pharo-project/pharo/pull/1835'de yeni değişti ve negatif sıfır ve nan davranışı için bir çeşit standart (IEC 60559 veya ISO 10967) dikte eden davranış olup olmadığını merak ettim ... javascript işareti developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/…
aka.nice

29

En yüksek puan alan çözümler de dahil olmak üzere yukarıdaki çözümlerden daha hızlı:

(x < 0) ? -1 : (x > 0)

1
X türü nedir? Yoksa #define mi kullanıyorsunuz?
Şans

3
Yazı tipiniz daha hızlı değil. Oldukça sık önbellek kaçmasına neden olur.
Jeffrey Drake

19
Önbellek özlüyor mu? Nasıl olduğundan emin değilim. Belki de şube yanlış tahmin etmek istediniz?
Catskul

2
Bana öyle geliyor ki bu, tamsayı ve boole türlerini karıştıran bir uyarı ile sonuçlanacak!
sergiol

şube ile bu nasıl hızlı olacak?
Nick

16

Dallanmadan yapmanın bir yolu var, ama çok hoş değil.

sign = -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));

http://graphics.stanford.edu/~seander/bithacks.html

Bu sayfadaki diğer ilginç, aşırı zekice şeyler de ...


1
Yalnızca -1 veya 0 döndüren bağlantıyı doğru okursam -1, 0 veya +1 istiyorsanız, o da sign = (v != 0) | -(int)((unsigned int)((int)v) >> (sizeof(int) * CHAR_BIT - 1));veya sign = (v > 0) - (v < 0);.
Z bozon

1
Bu vint
phuclv'den

12

İstediğiniz tek şey işareti test etmekse , signbit kullanın (bağımsız değişkeninin negatif işareti varsa true değerini döndürür). Neden özellikle -1 veya +1 döndürülmesini istediğinizden emin değilsiniz; copysign bunun için daha uygundur, ancak negatif sıfır için yalnızca kısmi desteğe sahip bazı platformlarda negatif sıfır için +1 döndürecek gibi görünüyor, burada signbit muhtemelen doğru dönecektir.


7
(X) işaretinin gerekli olduğu birçok matematiksel uygulama vardır. Yoksa sadece yapardım if (x < 0).
Şans

5

Genel olarak, C / C ++ 'da standart bir signum işlevi yoktur ve böyle temel bir işlevin olmaması, bu diller hakkında çok şey anlatır.

Bunun dışında, böyle bir işlevi tanımlamak için doğru yaklaşımla ilgili her iki çoğunluk görüşünün de doğru bir şekilde olduğuna inanıyorum ve iki önemli uyarıyı hesaba kattığınızda bununla ilgili "tartışma" aslında bir tartışma değil:

  • Bir signum işlevi her zaman işlevin türünü bir abs()işleve benzer şekilde döndürmelidir , çünkü signum genellikle bir şekilde işlendikten sonra mutlak bir değerle çarpma için kullanılır. Bu nedenle, signum'un ana kullanım durumu karşılaştırma değil aritmetiktir ve ikincisi, kayan noktadan / noktaya dönüşümler arasında pahalı bir tamsayı içermemelidir.

  • Kayan nokta türlerinde tek bir tam sıfır değeri bulunmaz: +0.0, "sonsuzdan sıfırın üstünde" ve -0.0, "sonsuzdan sıfırın altında" olarak yorumlanabilir. Bu nedenle sıfır içeren karşılaştırmalar, her iki değere karşı dahili olarak kontrol edilmelidir ve benzeri bir ifade x == 0.0tehlikeli olabilir.

C ile ilgili olarak, bence integral tiplerle ilerlemenin en iyi yolu, (x > 0) - (x < 0)ifadeyi dalsız bir şekilde tercüme edilmesi gerektiği için kullanmaktır ve sadece üç temel işlem gerektirir. Bağımsız değişken türüyle eşleşen bir dönüş türünü zorunlu kılan satır içi işlevleri en iyi şekilde tanımlayın ve bir C11 ekleyindefine _Generic bu işlevleri ortak bir adla .

Kayan nokta değeri ile, C11 dayalı satır içi işlevleri düşünüyorum copysignf(1.0f, x), copysign(1.0, x)ve copysignl(1.0l, x)gitmek için bir yoldur, onlar da konum çünkü büyük olasılıkla dal-özgür olmak ve kayan noktası haline tamsayı arkasından sonucu döküm gerektirmeyen ek değer. Muhtemelen sizin kayan nokta uygulamaları oldukça göze yorum gerekir sinyalnum zaman dikkat edilmesi gereken işleme, çünkü noktası sıfır değerlerini yüzen özelikleri sıfır döndürmez ve ayrıca almayı genellikle kayar nokta aritmetik çok faydalıdır çünkü doğru -1 / + Sıfır işareti için bile 1 işareti.


5

Özetle içindeki C kopyam, yararlı olabilecek copysign adı verilen standart bir işlevin varlığını ortaya koyuyor. Copysign (1.0, -2.0) -1.0 ve copysign (1.0, 2.0) +1.0 döndürür gibi görünüyor.

Oldukça yakın ha?


Standart değil, ancak yaygın olarak bulunabilir. Microsoft, standart olmayan uzantılar için kullandıkları kural olan bir alt çizgiyle başlar. Tamsayılarla çalışırken en iyi seçim değil.
Mark Ransom

5
copysign hem ISO C (C99) hem de POSIX standartlarındadır. Bkz. Opengroup.org/onlinepubs/000095399/functions/copysign.html
lhf

3
Ne dedi. Visual Studio, C standardı için bir başvuru değildir.
Stephen Canon

3

Hayır, matlab gibi c ++ 'da mevcut değildir. Bunun için programlarımda bir makro kullanıyorum.

#define sign(a) ( ( (a) < 0 )  ?  -1   : ( (a) > 0 ) )

5
C ++ 'da makrolara göre şablonlar tercih edilmelidir.
Ruslan


Bu iyi bir cevap olduğunu düşündüm sonra kendi koduma baktı ve buldum: #define sign(x) (((x) > 0) - ((x) < 0))ki çok iyi.
Michel Rouzic

1
satır içi işlev, C'deki bir makrodan daha iyidir ve C ++ şablonunda daha iyidir
phuclv

3

Aşağıdaki aşırı yük ile kabul edilen Cevap gerçekten -Wtype sınırlarını tetiklemez .

template <typename T> inline constexpr
  int signum(T x, std::false_type) {
  return T(0) < x;
}

template <typename T> inline constexpr
  int signum(T x, std::true_type) {
  return (T(0) < x) - (x < T(0));
}

template <typename T> inline constexpr
  int signum(T x) {
  return signum(x, std::is_signed<T>());
}

C ++ 11 için bir alternatif olabilir.

template <typename T>
typename std::enable_if<std::is_unsigned<T>::value, int>::type
inline constexpr signum(T const x) {
    return T(0) < x;  
}

template <typename T>
typename std::enable_if<std::is_signed<T>::value, int>::type
inline constexpr signum(T const x) {
    return (T(0) < x) - (x < T(0));  
}

Benim için GCC 5.3.1 ile ilgili herhangi bir uyarı almaz.


-Wunused-parameterUyarıyı önlemek için sadece isimsiz parametreler kullanın.
Jonathan Wakely

Aslında bu çok doğru. Onu özledim. Ancak, her iki şekilde de C ++ 11 alternatifini seviyorum.
SamVanDonut

2

Konu dışı biraz, ama bunu kullanın:

template<typename T>
constexpr int sgn(const T &a, const T &b) noexcept{
    return (a > b) - (a < b);
}

template<typename T>
constexpr int sgn(const T &a) noexcept{
    return sgn(a, T(0));
}

ve ilk işlevi buldum - iki argüman olan, "standart" sgn () çok daha yararlı olması için, çünkü en sık böyle kod kullanılır:

int comp(unsigned a, unsigned b){
   return sgn( int(a) - int(b) );
}

vs.

int comp(unsigned a, unsigned b){
   return sgn(a, b);
}

imzasız tipler için ek ve ek eksi yoktur.

aslında sgn () kullanarak kod bu parça var

template <class T>
int comp(const T &a, const T &b){
    log__("all");
    if (a < b)
        return -1;

    if (a > b)
        return +1;

    return 0;
}

inline int comp(int const a, int const b){
    log__("int");
    return a - b;
}

inline int comp(long int const a, long int const b){
    log__("long");
    return sgn(a, b);
}

1

Soru eski ama şimdi bu tür istenen bir işlev var. Değil, sola kaydırma ve dec ile bir sarıcı ekledim.

Dayalı bir sarıcı işlevi kullanabilirsiniz İstenen davranışı tam olarak elde etmek için C99'dan gelen uyarıya (aşağıdaki koda bakın).

X işaretinin negatif olup olmadığını döndürür.
Bu, sonsuzlara, NaN'lere ve sıfırlara da uygulanabilir (sıfır işaretsizse pozitif kabul edilir

#include <math.h>

int signValue(float a) {
    return ((!signbit(a)) << 1) - 1;
}

Not: Ben işlenen değil ("!") Kullanın çünkü signbit dönüş değeri 1 olarak belirtilmedi (örnekler her zaman bu şekilde olacağını düşünmemize rağmen) ama negatif bir sayı için doğru:

Geri dönüş değeri
x işareti negatifse sıfırdan farklı bir değer (true); ve sıfır (yanlış) aksi takdirde.

Sonra iki tarafa sola kaydırma ("<< 1") ile çarpıyorum, bu da bize pozitif bir sayı için 2, negatif bir sayı için 0 ve nihayetinde talep ettiği gibi pozitif ve negatif sayılar için 1 ve -1 elde etmek üzere 1'e düşer. OP.


0 o zaman da pozitif olacak ... OP'nin istediği olabilir veya olmayabilir ...
Antti Haapala

n = 0 ise OP'nin gerçekten ne istediğini asla bilemeyebiliriz!
Antonin GAVREL

0

Kabul edilen cevaptaki tamsayı çözüm oldukça zarif olsa da, çift tipler için NAN'ı döndüremeyeceği beni rahatsız etti, bu yüzden biraz değiştirdim.

template <typename T> double sgn(T val) {
    return double((T(0) < val) - (val < T(0)))/(val == val);
}

Sert kodlu aksine bir kayan nokta NAN dönen geldiğini hatırlatırız NANişaret bitidir ayarlanacak nedenleri bazı uygulamalarda için çıkış böylece, val = -NANve val = NANbir "tercih ederseniz gidiyor (ne olursa olsun aynı olduğu nanbir aşkın" çıkışını -nansen koyabilirsiniz bir abs(val)dönmeden önce ...)



0

İşte dallanma dostu bir uygulama:

inline int signum(const double x) {
    if(x == 0) return 0;
    return (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

Verileriniz sayıların yarısı kadar sıfır değilse, burada dal tahmincisi dallardan birini en yaygın olarak seçecektir. Her iki dalda sadece basit operasyonlar vardır.

Alternatif olarak, bazı derleyiciler ve CPU mimarilerinde tamamen dalsız bir versiyon daha hızlı olabilir:

inline int signum(const double x) {
    return (x != 0) * 
        (1 - (static_cast<int>((*reinterpret_cast<const uint64_t*>(&x)) >> 63) << 1));
}

Bu, IEEE 754 çift kesinlikli ikili kayan noktalı biçim için çalışır: binary64 .


-1
int sign(float n)
{     
  union { float f; std::uint32_t i; } u { n };
  return 1 - ((u.i >> 31) << 1);
}

Bu işlev varsayar:

  • binary32kayan nokta sayılarının gösterimi
  • adlandırılmış bir birleşim kullanırken katı örtüşme kuralı hakkında bir istisna oluşturan bir derleyici

3
Burada hala bazı kötü varsayımlar var. Örneğin, şamandıranın endianitesinin, tamsayının endianitesi olduğuna inanmıyorum. Ayrıca çekiniz ILP64 kullanan mimarilerde başarısız olur. Gerçekten, sadece yeniden uyguluyorsunuz copysign; kullanıyorsanız static_assert, C ++ 11'iniz var ve gerçekten de kullanabilirsiniz copysign.

-3
double signof(double a) { return (a == 0) ? 0 : (a<0 ? -1 : 1); }

-3

Üçlü işleçleri neden kullanıyorsunuz?

#define sgn(x) x==0 ? 0 : x/abs(x)

3
Tanımınızda üçlü bir operatör de kullanılıyor.
Martin R

Evet Kesinlikle, ancak sıfır ve sıfır olmayan sayıları ayırmak için sadece bir üçlü operatör kullanır. Diğerlerinin sürümleri pozitif, negatif ve sıfırı ayırmak için iç içe üçlü ops içerir.
Jagreet

Bir tamsayı bölümü kullanmak çok verimsizdir ve abs () sadece tamsayılar içindir.
Michel Rouzic

Tanımsız davranış mümkün olduğunda x == INT_MIN.
chux - Monica adlı kullanıcıdan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.