2009-03-03 14 views
32

Ben sözdizimistd :: floor'dan sonra bir int için doğru sonucu garanti ediyor mu?

int floor(double x); 

ama doublestd::floor döndüren bir floor fonksiyonunu istiyorum.

static_cast <int> (std::floor(x)); 

bana doğru tamsayı vermeyi garanti, ya da ben bir off-birer sorunu olabilir? Çalışıyor gibi görünüyor, ama emin olmak isterim.

bonus puan için

, neden halt ilk etapta bir double dönmek std::floor yapar?

cevap

25

Çift aralık, 32 veya 64 bit tam sayı aralığında olduğundan daha büyüktür, bu nedenle std::floor, double değerini döndürür. int için Döküm uygun aralıkta bulunuyor sürece iyi olmalı - ama double tam olarak tüm 64 bit tamsayı temsil edemez unutmayın, bu nedenle noktanın ilerisine gitmek zaman da hatalar ile sona erebilir hangi doğruluğu en double iki ardışık çift arasındaki fark, evet hemen hemen istediğini yapar büyüktür 1.

+0

doğru aralıkta parça varsa, dökme o spec bu (ima şey) diyor nerede gayet? ? –

+0

Burada iki işlem var: std :: floor ve cast. Std :: floor bir tamsayı döndürecek ve cast bir tamsayı değeriyle belirtildi. Std :: floor döndüğü sürece Gerçekten tam bir tamsayı olan bir değer, ben Başarısızlığın nasıl mantıklı olacağını göremiyorum. –

+0

Kat, tam bir tam sayı olmayan bir şeyi nasıl iade ederdi? Küçük çiftler için (epsilon << 1), zemin (x) dahil olmak üzere tüm ayrılmaz değerler gösterilebilir. Büyük çiftler için (epsilon >> 1), sadece integral değerler gösterilebilir, bu yüzden kat (x) == x. – MSalters

12
static_cast <int> (std::floor(x)); 

olduğu şekildedir. Size en yakın tam sayıyı -infinity'ye doğru yuvarlar. En azından girişiniz, ints tarafından temsil edilen aralıkta olduğu sürece. '.5 ve neyi ekleyerek neyi kastettiğinizden emin değilim, ancak aynı etkiye sahip olmayacağından emin değilim.

Ve std :: kat bir çift döndürüyor çünkü bu en genel olanı. Bazen bir yüzdeyi veya iki katını yuvarlamak isteyebilirsiniz, ancak türü koruyabilirsiniz. Yani yuvarlak ziyade Yani std :: zemin bir int döndü eğer yapmak zor olurdu 1.

daha, 1.0f için 1.3f vardır. (ya da en azından, orada yavaşlayan şeyleri gereksiz yere attıracaksınız).

kat yalnızca türünü değiştirmeden, kendisini yuvarlama, size gerektiğinde/eğer int yayınlayabileceğim gerçekleştirir.

diğer nedeni çiftlerde aralığı ints çok daha büyük olmasıdır. Tüm çiftlerin inçlere yuvarlanması mümkün olmayabilir.

+1

kat(), sıfıra doğru değil, sıfırdır: Bkz. Http://www.cplusplus.com/reference/clibrary/cmath/floor.html –

+0

doh, tabi ki haklısınız. Sabit. – jalf

5

Çeşitli sayısal koşullarla uğraşmak istiyorsanız ve farklı bir dönüşüm türünü kontrollü bir şekilde ele almak istiyorsanız, belki de Boost.NumericConversion'a bakmalısınız. Bu kütüphane (out-of-aralık, yuvarlama, aralıkları, vb gibi) İşte

belgelerinden örnek garip davalarını sağlar:

#include <cassert> 
#include <boost/numeric/conversion/converter.hpp> 

int main() { 

    typedef boost::numeric::converter<int,double> Double2Int ; 

    int x = Double2Int::convert(2.0); 
    assert (x == 2); 

    int y = Double2Int()(3.14); // As a function object. 
    assert (y == 3) ; // The default rounding is trunc. 

    try 
    { 
     double m = boost::numeric::bounds<double>::highest(); 
     int z = Double2Int::convert(m); // By default throws positive_overflow() 
    } 
    catch (boost::numeric::positive_overflow const&) 
    { 
    } 

    return 0; 
} 
2

standart matematik kütüphanesinin çoğu kullanır çiftler ancak Şamandıra versiyonları da sağlar. std :: floorf(), iki katı kullanmamanızı tercih ederseniz std :: floor() öğesinin tek duyarlıklı sürümüdür.

Düzenleme: Önceki yanıtımın bir kısmını kaldırdım. Int'e intikam ederken zeminin gereksiz olduğunu belirttim, ancak bunun sadece pozitif kayan noktalı sayılar için doğru olduğunu unutmuştum.

6

C++ standart söyler (4.9.1):

"kayan nokta tür bir rvalue bir tamsayı tür bir rvalue dönüştürülebilir dönüşüm keser, yani kesirli kısmı iptal edilir..Kesilen değer hedef türünde gösterilemiyorsa, davranış tanımsızdır ".

Bu nedenle, bir int'ye bir çift dönüştürüyorsanız, sayı int'nin aralığındadır ve gerekli yuvarlama sıfıra doğru olur. o zaman int basitçe numarayı döküm için yeterlidir:

(int) x;

+0

Kesir kısmının kesilmesi zemin değildir - sonuç negatif sayılar için farklıdır. – Suma

+0

Açıkça yazdım ki "eğer gerekli ... yuvarlama işlemi sıfıra yaklaşıyorsa" bu durumu "yuvarlamadan -infinity'ye" doğru ayırmak için. Zemin -infinity'ye doğru yuvarlanıyor, kesiliyor - sıfıra doğru. –

İlgili konular