0 ile -0 arasında ayrım yapmak mümkün mü?


94

O tam sayı değerlerini biliyoruz 0ve -0esasen aynıdır. Ama aralarında ayrım yapmanın mümkün olup olmadığını merak ediyorum.

Örneğin, bir değişkenin atanıp atanmadığını nasıl anlarım -0?

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

-0Hafızaya kaydedilen değer ile aynı şekilde 0mi?


9
Tam sayılar için fark yoktur.
Maroun

14
Bu, uygulamaya bağlıdır, ancak int2'nin tamamlayıcısında (açık ara en sık karşılaşılan) temsil edilen 0ve -0aynı bitsel gösterimlere sahip uygulamalar için.
Mankarse

11
2'nin tamamlayıcı makinesinde bit düzeyinde hiçbir fark yoktur.
Marco A.

17
@VirtualSnake: "İkilide" ne anlama geliyor? Orada, aslında, ikili kodlamaları kendisi için orada olan Sign ve genliği arasındaki -0 ve 0., örneğin bir ayrım.
Benjamin Lindley

8
@VirtualSnake Doğru, bahsediyoruz int. Birlerin tamamlayıcı kodlamasına bakın .
CiaPan

Yanıtlar:


112

Hedeflediğiniz makineye bağlıdır.

Tamsayılar için 2'nin tümleyen gösterimini kullanan bir makinede, ve arasında bit düzeyinde fark yoktur (aynı gösterime sahiptirler)0-0

Makineniz birinin tamamlayıcısını kullandıysa , kesinlikle

0000 0000   -> signed01111 1111   -> signed0

Açıkçası , yerel destek kullanmaktan bahsediyoruz , x86 serisi işlemciler, imzalı sayıların ikisinin tamamlayıcı temsili için yerel desteğe sahip. Diğer temsilleri kullanmak kesinlikle mümkündür, ancak muhtemelen daha az verimli olacaktır ve daha fazla talimat gerektirecektir.

(JerryCoffin'in de belirttiği gibi: Bir kişinin tümleyeni çoğunlukla tarihsel nedenlerle düşünülse bile, imzalı büyüklük temsilleri hala oldukça yaygındır ve negatif ve pozitif sıfır için ayrı bir temsilleri vardır)


6
@TobiMcNamobi: Endişelenecek kadar olası değil. Hiç kimse böyle bir makine için çıktı üretmek için bir C ++ derleyicisini kullanmaya zahmet etse şaşırırdım.
Benjamin Lindley

1
Benjamin'e katılıyorum, tarihsel olarak onu kullanan makineler vardı, ancak bugünlerde onu kullanan üretim makinelerini bilmiyorum. Yine de bilmek ve akılda tutmak her zaman iyidir.
Marco A.

4
@TobiMcNamobi birinin tamamlayıcısı UNISYS 2200 sistem stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv

2
Ben kişinin tamamlayıcı gereksinimleri baktım hiç - does standart aslında garanti olduğunu 0ve -0olan farklı ? Dürüst olmak gerekirse, aynı değerin iki bitlik gösterimine izin veriyormuş gibi davranmasını beklerdim ve programınız hangisi gibi hissediyorsa onu kullanabilir.

8
@Hurkly: hayır, negatif bir sıfır gösterimi olsa bile standart, ifadeyi kullanan atama veya başlatmanın -0, yani tekli -operatörü tamsayı sabitine uygulamanın sonucunun negatif bir sıfır gösterimi olduğunu garanti etmez 0. Temsile bakılmaksızın, standart asla söylemez 0ve -0matematiksel olarak farklı değerlerdir, sadece negatif-sıfır bit modeli olabilir. Varsa, hala aynı sayısal değeri, 0 değerini temsil eder
Steve Jessop

14

Bir int(neredeyse evrensel "2'nin tümleyen" temsilinde) için temsiller 0ve -0aynıdır. (Diğer sayı gösterimleri için farklı olabilirler, örneğin IEEE 754 kayan nokta.)


9
>> 2'nin tümleyen temsilini varsayarsak
Marco A.

12

0'ı 2'nin tamamlayıcısında temsil etmekle başlayalım (tabii ki başka birçok sistem ve temsil var, burada bu spesifik olanı kastediyorum), 8-bit varsayarsak, sıfır:

0000 0000

Şimdi tüm bitleri ters çevirelim ve 2'nin tümleyenini elde etmek için 1 ekleyelim:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

aldık 0000 0000ve bu da -0'ın temsilidir.

Ancak, 1'in tümleyeninde 0 işaretinin 0000 0000, ancak -0'ın 1111 1111 olduğuna dikkat edin.


1
Cevabımı iyileştirmek için neden olumsuz oy kullandığını öğrenebilir miyim lütfen?
Maroun

1
Diğer cevapların çoğu teknik olarak doğru olsa da, cevabınız pratiktir ve bir uygulama sağlar. İyi.
umlcat

9

C ve C ++ uygulamaları genellikle yakından ilişkili olduğu için bu yanıtı bırakmaya karar verdim, ancak aslında düşündüğüm gibi C standardına ertelemiyor. Önemli olan nokta, C ++ standardının bu gibi durumlar için ne olacağını belirtmemesidir. Aynı zamanda, iki-tamamlayıcı olmayan temsillerin gerçek dünyada son derece nadir olması ve var oldukları yerde bile, çoğu durumda, birisinin kolayca keşfetmeyi bekleyebileceği bir şey olarak ortaya çıkarmak yerine, çoğu durumda farkı gizledikleri de önemlidir.


Negatif sıfırların içinde bulundukları tamsayı temsillerindeki davranışı, C ++ standardında C standardında olduğu kadar titiz bir şekilde tanımlanmamıştır. Bununla birlikte, C standardını (ISO / IEC 9899: 1999) en üst düzeyde [1.2] normatif bir referans olarak göstermektedir.

C standardında [6.2.6.2], negatif sıfır yalnızca bitsel işlemlerin veya negatif sıfırın zaten mevcut olduğu işlemlerin sonucu olabilir (örneğin, negatif sıfırın bir değerle çarpılması veya bölünmesi veya eksi sıfırın eklenmesi sıfır) - tekli eksi operatörünü, örneğinizde olduğu gibi normal bir sıfır değerine uygulamak, bu nedenle normal bir sıfırla sonuçlanacağı garanti edilir.

Hatta durumlarda olabilir bir negatif sıfır oluşturmak, hatta destek negatif sıfır yapan bir sistem üzerinde, hiçbir garantisi durumun böyle olacağını vardır:

Bu durumların gerçekte bir negatif sıfır mı yoksa normal bir sıfır mı oluşturduğu ve bir nesnede depolandığında negatif sıfırın normal sıfır olup olmadığı belirtilmemiştir.

Bu nedenle şu sonuca varabiliriz: hayır, bu vakayı tespit etmenin güvenilir bir yolu yok. Modern bilgisayar sistemlerinde iki tamamlayıcı olmayan temsillerin çok nadir olduğu gerçeği olmasa bile.

C ++ standardı, kendi adına, "negatif sıfır" teriminden hiç bahsetmez ve işaretli büyüklük ve kişinin tamamlayıcı temsillerinin ayrıntılarına ilişkin çok az tartışmaya sahiptir, bunlara izin verildiği not [3.9.1 para 7] dışında.


Yok Genel olarak, şey gerçek olması / C gerekli değildir mutlaka ++ doğru / C gereklidir demek. C'nin normatif bir referans olduğu gerçeği, C ++ 'nın çeşitli şeyler için C standardına atıfta bulunduğu anlamına gelir (esas olarak standart başlıkların içeriği), ancak tam sayı türlerinin tanımı bunlardan biri değildir. Bununla birlikte, negatif sıfırı üretmenin garantili bir yolunun yokluğu, sonuca vardığınız şeyin hala doğru olduğu anlamına gelir, temsil mevcut olsa bile aritmetik kullanarak bir tane oluşturmanın kesin bir yolu yoktur.
Steve Jessop

Öyleyse neden C ++ standardı böyle şeyler hakkında çok daha az ayrıntıya giriyor?
Random832

1
Kişisel zevk, bence, C ++ standardına oy veren kişi sayısı "kişisel" olarak kabul edilebilirse :-) Tanımlar için C standardına ertelenecek olsaydı, o zaman uygun bir iş çıkarabilirdi. ve diğer bazı durumlarda olduğu gibi hiçbir ayrıntı içermez .
Steve Jessop

"C ++, ISO / IEC 9899: 1999 Programlama dillerinde - C (bundan sonra C standardı olarak anılacaktır) açıklandığı gibi C programlama dilini temel alan genel amaçlı bir programlama dilidir." [1.1 para 2] herhangi bir normatif anlamı var mı? Bunun genellikle C ++ standardı tarafından özellikle geçersiz kılınmayan herhangi bir şey için C standardını dahil etmesi amaçlandığını düşündüm.
Random832

Random832 sayılı bu sadece tarihsel not @ (örneğin, orada, bir _Boolya da _Complexya da atanmış başlangıç veya C bileşik değişmez ++). C ++ standardı, istediğinde C standardını nasıl dahil edeceğini bilir - örneğin, [temel. Temel] / p3: "İşaretli ve işaretsiz tam sayı türleri, C standardı, bölüm 5.2.4.2.1'de verilen kısıtlamaları karşılamalıdır."
TC

8

Makineniz için farklı gösterime sahipse -0ve +0daha sonra memcmpbunları ayırt etmek mümkün olacak.

Dolgu bitleri mevcutsa, aslında sıfır dışındaki değerler için de çoklu temsiller olabilir.


5

C ++ dil belirtiminde, negatif sıfır diye bir int yoktur .

Sadece bu iki kelime var anlamına tekli bir operatördür -uygulanan 0gibi, üç artı beş sadece ikili operatörüdür +uygulanan 3ve 5.

Farklı bir negatif sıfır varsa , ikinin tümleyicisi (tamsayı türlerinin en yaygın temsili), sıfırın iki biçimini temsil etmenin bir yolu olmadığından, C ++ uygulamaları için yetersiz bir temsil olacaktır.


Bunun aksine, kayan noktaların (IEEE'yi takiben) ayrı pozitif ve negatif sıfırları vardır. Örneğin, 1'i kendileriyle bölerken ayırt edilebilirler. Pozitif sıfır, pozitif sonsuzluk üretir; negatif sıfır, negatif sonsuzluk üretir.


Bununla birlikte, int 0'ın (veya herhangi bir int veya herhangi bir başka türden herhangi bir değer) farklı bellek temsilleri varsa, şunu memcmpkeşfetmek için kullanabilirsiniz :

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}

Tabii ki, eğer bu gerçekleşirse, doğrudan bellek işlemlerinin dışında, iki değer hala aynı şekilde çalışırdı.


3
Aslında, varlığını zorunlu kılmayan dil, onun yokluğunu zorunlu kıldığı anlamına gelmez. İpucu: İkisini de zorunlu kılmaz.
Tekilleştirici

2
@Deduplicator, bir çeşit. "C ++ dilinde" derken, "C ++ dil belirtiminde " demek istiyorum . Spesifikasyonda froobinators'dan da söz edilmediğinden, çok fazla belirsizlik olmadan "C ++ froobinators'a sahip değildir" diyebilirim. Bunun açık olduğunu düşündüm, ama onu geliştireceğim.
Paul Draper

1
Dil özellikleri de tek boynuzlu atlardan bahsetmiyor.
ypercubeᵀᴹ

2

Basitleştirmek için görselleştirmeyi daha kolay buldum.

Tür int (_32) 32 bit ile saklanır . 32 bit, 2 ^ 32 = 4294967296 benzersiz değer anlamına gelir . Böylece :

işaretsiz int veri aralığı 0 - 4,294,967,295

Negatif değerler olması durumunda, nasıl depolandıklarına bağlıdır. Bu durumda

Durumunda One tamamlayıcı değeri -0 bulunmaktadır.


2
Olumsuz oy vermedim ama int32 bit olarak saklanmayan platformlar, günümüzde tamamlayıcı olan platformlardan daha popüler.
Maciej Piechotka
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.