2016-07-13 80 views
5

Ben takip eden bir C ifadesi (değişkenler, 32 bit yüzen)Kayan nokta sıfır Cı uygulamalarında (IEEE 754 değişmezler?)

float result = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 

varsayılarak x0==x1 ve y0==y1 (ve == ile İkili demek temsil kimliği), ifadenin mutlaka sıfır olarak değerlendirileceğine güvenebilir miyim (floatın tüm bitleri 0 olarak ayarlanmışsa)? Başka bir deyişle, değişmezlerin peşinden koşmanın her zaman beklediğini varsayabilir miyim?

memcmp(&a, &b, sizeof(float) == 0 => memcmp(a-b, (uint32_t)0, sizeof(float)) == 0 
0*a == 0.0 

Bütün değerlerin sonlu sayılar (hayır SONSUZ veya NaN) olduğunu varsaymak güvenlidir.

Düzenleme: Yanıtlarda belirtildiği gibi, 0 ile çarpımlar imzalı sıfırlar üretebilir. memcmp iyi bir sorum göstermek için çağırır tarafından değiştirildi tip atmalarını: Hala ifadenin sonucu FP-karşılaştırma kurallarını kullanarak 0.0 eşit olacağı gerçeği, yani .:

(result == 0.0) 

düzenleme 1 güvenebilirsiniz.

P.S. Herhangi bir fark yaratırsam, kodumu yalnızca uyumlu C11 derleyicileriyle sınırlandırıyorum. Ayrıca, bu durumumda yardımcı olacaksa, STDC_IEC_559 desteğine güvenmeye istekliyim.

+0

Ayrıca 'y2 - y0' ve 'x2 - x0' sonlu olacağını varsayabilir miyiz? –

+0

@OliverCharlesworth: evet. Değilse, undefined olan sonuçlarla birlikte iyiyim. – MrMobster

+0

Hangi tür 'a' ve' b'? Eğer 'uint32_t' değilse, kodunuz tanımlanmamış bir davranışı çağırır (etkin tip kuralının ihlali). Standart tarafından her şeye izin verilir."Sıfırla" – Olaf

cevap

4

C11'e değinmek, yalnızca IEEE 754'ün herhangi bir C standardı gerektirmediği için sorunuzu karıştırır.

, sadece sonucun tüm bitleri olacağını kabul edemeyiz IEEE 754 32 bit kayan nokta sayıları varsayarak ve (onlara sonsuz veya NaN olmayan başka) x2 ve y2 üzerinde hiçbir varsayımlarda söyleniyor 0 IEEE 754 sayıları bir negatif ve bir pozitif olmak üzere iki sıfır değerine sahiptir ve (y2 - y0) - (x2 - x0) ifadesi negatif ise, sıfır ile çarpma sonucu negatif bir sıfır olacaktır.

Biz bu kısa örnekle test edebilirsiniz:

#include <stdio.h> 
#include <stdint.h> 

int 
main(int argc, char **argv) 
{ 
    union { 
     float f; 
     uint32_t i; 
    } foo; 

    float a = 0; 
    float b = -1; 

    foo.f = a * b; 
    printf("0x%x\n", foo.i); 

    return 0; 
} 

sonuç (ben akıllı olmaya derleyici istemiyoruz çünkü hiçbir optimizasyonları dikkat edin):

$ cc -o foo foo.c && ./foo 
0x80000000 

Oh, sadece "Başka bir deyişle" dediğiniz ikinci bölümün aslında başka bir deyişle, başka bir soru olmadığı için fark edilmediğini fark ettiniz.

(*(uint32_t*)(&a) == *(uint32_t*)(&b)) 

-0 == 0 çünkü kayan nokta için a == b eşdeğer değildir:

ile başlayın. Ve bununla birlikte, varsayımın diğer kısmı, -0 - 0 size -0'u verdiğinden dolayı düşer. Eşit sayıların negatif bir sıfır oluşturduğu başka bir çıkarma yapamıyorum, ancak bunun mümkün olmadığı anlamına gelmiyor, standartların tüm uygulamalarda çıkarma için aynı algoritmayı zorlamadığından eminim ki işaret biti, bir şekilde oraya gizlice girebilir.

+0

Bu "negatif sıfır" şey ile iyi yakalayın. Aslında cevabın Evet olacağını (sizinkini okumadan önce) tahmin ediyorum. –

+0

Teşekkürler, Art! Tabii ki IEEE standardından bahsetmek biraz yanıltıcıdır. En çok ilgilendiğim şey, ortak donanım üzerinde ek kimlik kontrolleri yapmamın, ortak C11 derleyicileriyle mi yoksa çekleri güvenli bir şekilde atlayıp atlayamayacağımı mı bilmem gerektiğidir. İmzalı sıfır yorum çok faydalı! Ben 'sıfır bit-pattern' sıfır yerine 0 ile FP karşılaştırma yaparak tamam olur. Bu güvenli olur mu? – MrMobster

+0

@MrMobster Kayan nokta sayısını sıfır ile karşılaştırmak için en güvenli bahsiniz a == 0.0'. Olumsuz veya pozitif olursa olsun bu işe yarayacaktır. – Art