सी में नैनो और इनफिनिटी का उपयोग कैसे करें?


89

मेरे पास एक संख्यात्मक विधि है जो अगर कोई त्रुटि थी तो वह नान या इनफ्लिट कर सकती है, और इस उद्देश्य के परीक्षण के लिए कि मैं अस्थायी रूप से इसे वापस लौटने के लिए मजबूर करना चाहता हूं ताकि यह सुनिश्चित हो सके कि स्थिति को सही तरीके से संभाला जा सके। क्या सी में नैन और इन्फ्यूजन के मान बनाने के लिए एक विश्वसनीय, संकलक-स्वतंत्र तरीका है?

लगभग 10 मिनट तक गुगली करने के बाद मैं केवल कंपाइलर निर्भर समाधान खोजने में सक्षम हुआ हूं।


फ्लोट्स सी मानक द्वारा परिभाषित नहीं हैं। इसलिए जो आप चाहते हैं उसे करने का कोई कंपाइलर-स्वतंत्र तरीका नहीं है।
जोहान कोटलिंस्की

जवाबों:


86

आप परीक्षण कर सकते हैं कि आपके कार्यान्वयन में यह है:

#include <math.h>
#ifdef NAN
/* NAN is supported */
#endif
#ifdef INFINITY
/* INFINITY is supported */
#endif

के अस्तित्व की INFINITYगारंटी C99 (या कम से कम नवीनतम ड्राफ्ट) द्वारा दी गई है, और "टाइप फ्लोट की एक स्थिर अभिव्यक्ति के लिए फैलता है, जो सकारात्मक या अहस्ताक्षरित अनंत का प्रतिनिधित्व करता है, यदि उपलब्ध हो, तो अनुवाद के समय में ओवरफ्लो होने वाले टाइप फ़्लोट के सकारात्मक निरंतर के लिए।"

NAN हो सकता है या परिभाषित नहीं किया जा सकता है, और "परिभाषित किया गया है और केवल अगर कार्यान्वयन फ्लोट प्रकार के लिए शांत NaNs का समर्थन करता है। यह एक शांत NaN का प्रतिनिधित्व करने वाले प्रकार फ़्लोट के निरंतर अभिव्यक्ति का विस्तार करता है।"

ध्यान दें कि यदि आप फ्लोटिंग पॉइंट मानों की तुलना कर रहे हैं, और करें:

a = NAN;

फिर भी,

a == NAN;

गलत है। NaN के लिए जाँच करने का एक तरीका होगा:

#include <math.h>
if (isnan(a)) { ... }

आप यह भी कर सकते हैं: a != aपरीक्षण करने के लिए यदि aNaN है।

वहाँ भी है isfinite(), isinf(), isnormal(), और signbit()मैक्रो का math.hC99 में।

C99 के भी nanकार्य हैं:

#include <math.h>
double nan(const char *tagp);
float nanf(const char *tagp);
long double nanl(const char *tagp);

(संदर्भ: n1256)

डॉक्स इन्फिनिटी डॉक्स नान


2
बहुत बढ़िया जवाब। NAN और INFINITY मैक्रोज़ का संदर्भ C99 .127.12 पैरा 4 और 5 है। इसके अलावा (isnan (a)) आप C. के अनुरूप कार्यान्वयन पर NaN ((! A) के प्रयोग से भी देख सकते हैं
स्टीफन कैनन

23
पठनीयता के प्यार के लिए, कभी भी उपयोग नहीं किया a != aजाना चाहिए ।
क्रिस Kerekes

1
@ChrisKerekes: दुख की बात है कि हममें से कुछ के पास नन नहीं है, लेकिन इस्नान () है। हाँ, यह 2017 है। :(
eff 12

सी की आवश्यकता नहीं है, जब aएक नंबर नहीं है, a == NANझूठे लौटने के लिए । IEEE को इसकी आवश्यकता होती है। यहां तक ​​कि कार्यान्वयन जो IEEE का पालन करते हैं, ज्यादातर ऐसा करते हैं । जब isnan()लागू नहीं किया जाता है, तब भी सीधे कोड की तुलना में परीक्षण को लपेटना बेहतर होता है a == NAN
chux -

34

ऐसा करने का कोई भी स्वतंत्र तरीका नहीं है, क्योंकि न तो C (न ही C ++) मानकों का कहना है कि फ्लोटिंग पॉइंट गणित के प्रकारों को NAN या INF का समर्थन करना चाहिए।

संपादित करें: मैंने अभी C ++ मानक के शब्दांकन की जाँच की, और यह कहता है कि ये कार्य (templated वर्ग के सदस्य_संख्याएँ):

quiet_NaN() 
signalling_NaN()

wiill NAN अभ्यावेदन "यदि उपलब्ध हो"। यह "यदि उपलब्ध है" का अर्थ क्या है पर विस्तार नहीं करता है, लेकिन संभवतः कुछ ऐसा है जैसे "यदि कार्यान्वयन का एफपी प्रतिनिधि उनका समर्थन करता है"। इसी तरह, एक समारोह है:

infinity() 

जो "उपलब्ध होने पर" एक सकारात्मक INF प्रतिनिधि लौटाता है।

इन दोनों को <limits>हेडर में परिभाषित किया गया है - मुझे लगता है कि सी मानक में कुछ समान है (शायद "यदि उपलब्ध है") भी लेकिन मेरे पास वर्तमान सी 99 मानक की एक प्रति नहीं है।


यह निराशाजनक और आश्चर्यजनक है। C और C ++ IEEE फ़्लोटिंग पॉइंट नंबरों के अनुरूप नहीं है, जिसमें नैन और इनफ़ के लिए एक मानक प्रतिनिधित्व है?
ग्राफिक्स Noob

14
C99, सी शीर्षक में <math.h>परिभाषित करता है nan(), nanf()और nanl()NaN की कि वापसी विभिन्न अभ्यावेदन (एक के रूप में double, floatऔर intक्रमशः), और अनंत (यदि उपलब्ध है) के साथ एक उत्पन्न करके लौटे किया जा सकता है log(0)या कुछ और। C99 में भी उनके लिए कोई मानक तरीका नहीं है। <float.h>हैडर ( <limits.h>अभिन्न प्रकार के लिए है) के बारे में दुर्भाग्य से खामोश है infऔर nanमूल्यों।
क्रिस लूत्ज

वाह, यह एक बड़ा मिश्रण है। nanl()एक रिटर्न long double, intमेरी टिप्पणी की तरह नहीं कहता है। मुझे नहीं पता कि मुझे यह क्यों महसूस नहीं हुआ कि जब मैं इसे टाइप कर रहा था।
क्रिस लुत्ज़

@ क्रिस, C99 के लिए मेरा जवाब देखें।
आलोक सिंघल

2
@IngeHenriksen - बहुत यकीन है कि माइक्रोसॉफ्ट ने कहा है कि उसका वीसी ++ का समर्थन करने का कोई इरादा नहीं है।
क्रिस लूत्ज़

24

यह दोनों के लिए काम करता है floatऔर double:

double NAN = 0.0/0.0;
double POS_INF = 1.0 /0.0;
double NEG_INF = -1.0/0.0;

संपादित करें: जैसा कि किसी ने पहले ही कहा था, पुराने IEEE मानक ने कहा कि इस तरह के मूल्यों में जाल बढ़ाना चाहिए। लेकिन नए कंपाइलर लगभग हमेशा जाल को बंद कर देते हैं और दिए गए मानों को वापस कर देते हैं क्योंकि ट्रैपिंग त्रुटि से निपटने में हस्तक्षेप करता है।


754-1985 के तहत त्रुटि से निपटने के लिए ट्रैपिंग एक विकल्प था । अधिकांश आधुनिक हार्डवेयर / कंपाइलरों द्वारा उपयोग किए जाने वाले व्यवहार को भी अनुमति दी गई (और समिति के कई सदस्यों के लिए पसंदीदा व्यवहार था)। कई कार्यान्वयनकर्ताओं ने गलत तरीके से माना कि मानक में "अपवाद" शब्द के दुर्भाग्यपूर्ण उपयोग के कारण फंसाने की आवश्यकता थी। संशोधित 754-2008 में इसे बहुत स्पष्ट किया गया है।
स्टीफन कैनन

हाय, स्टीफन, आप सही कह रहे हैं, लेकिन मानक यह भी कहता है: "एक उपयोगकर्ता को इसके लिए एक हैंडलर निर्दिष्ट करके पांच अपवादों में से किसी पर एक जाल का अनुरोध करने में सक्षम होना चाहिए। वह अनुरोध कर सकता है कि एक मौजूदा हैंडलर को निष्क्रिय कर दिया जाए। , बचाया, या बहाल किया गया है। वह यह भी निर्धारित करने में सक्षम होना चाहिए कि निर्दिष्ट अपवाद के लिए एक विशिष्ट जाल हैंडलर सक्षम किया गया है या नहीं। " "परिभाषित" के रूप में (2. परिभाषाएँ) का अर्थ है "दृढ़ता से अनुशंसित" और इसके कार्यान्वयन को केवल तभी छोड़ा जाना चाहिए जब वास्तुकला आदि इसे अव्यवहारिक बनाती है। 80x86 पूरी तरह से मानक का समर्थन करता है, इसलिए सी के पास इसका समर्थन नहीं करने का कोई कारण नहीं है।
थोरस्टेन एस।

मैं सहमत हूं कि सी को 754 (2008) फ्लोटिंग पॉइंट की आवश्यकता होनी चाहिए, लेकिन इसके न होने के अच्छे कारण हैं; विशेष रूप से, C का उपयोग सभी प्रकार के वातावरणों में किया जाता है, जो x86 के अलावा - एम्बेडेड उपकरणों सहित जिसमें हार्डवेयर फ़्लोटिंग-पॉइंट नहीं है, और सिग्नल प्रोसेसिंग डिवाइस हैं जहाँ प्रोग्रामर फ़्लोटिंग पॉइंट का उपयोग नहीं करना चाहते हैं। सही या गलत तरीके से, जो भाषा की कल्पना में बहुत जड़ता के लिए खाते का उपयोग करते हैं।
स्टीफन कैनन

मुझे नहीं पता कि शीर्ष उत्तर ने इसे क्यों बनाया। यह अनुरोधित मानों का उत्पादन करने का कोई तरीका नहीं देता है। यह उत्तर देता है।
ड्राईडम

#define is_nan(x) ((x) != (x))नान के लिए एक सरल, पोर्टेबल परीक्षण के रूप में उपयोगी हो सकता है।
बॉब स्टीन

21

एक कंपाइलर स्वतंत्र तरीका है, लेकिन इन पाने के लिए स्वतंत्र तरीके से प्रोसेसर नहीं है:

int inf = 0x7F800000;
return *(float*)&inf;

int nan = 0x7F800001;
return *(float*)&nan;

यह किसी भी प्रोसेसर पर काम करना चाहिए जो IEEE 754 फ्लोटिंग पॉइंट फॉर्मेट (जो x86 करता है) का उपयोग करता है।

अद्यतन: परीक्षण और अद्यतन।


2
@AffleMatt - 32/64 बिट के बीच यह पोर्ट क्यों नहीं होगा? IEEE 754 एकल-सटीक फ्लोट अंतर्निहित प्रोसेसर के पते के आकार की परवाह किए बिना 32-बिट है।
हारून

6
के लिए कास्टिंग (float &)? यह मेरे लिए सी की तरह नहीं दिखता है। आप की जरूरत हैint i = 0x7F800000; return *(float *)&i;
क्रिस लुट्ज़

6
ध्यान दें कि IEEE-754 मानक में एक 0x7f800001तथाकथित संकेतन NaN है। यद्यपि अधिकांश पुस्तकालय और हार्डवेयर NaNs को संकेत देने का समर्थन नहीं करते हैं, लेकिन एक शांत NaN जैसे वापस लौटना बेहतर है 0x7fc00000
स्टीफन कैनन

6
चेतावनी: यह सख्त अलियासिंग नियमों के उल्लंघन के माध्यम से अपरिभाषित व्यवहार को ट्रिगर कर सकता है। संघ के सदस्यों के माध्यम से टाइपिंग करने के लिए अनुशंसित (और सर्वोत्तम समर्थित कंपाइलर) तरीका है ।
ulidtko

2
@Ulidtko ने कहा कि सख्त अलियासिंग मुद्दे के अलावा, यह मानता है कि लक्ष्य पूर्णांक के लिए एक ही एंडियन का उपयोग फ्लोटिंग पॉइंट के रूप में करता है, जो निश्चित रूप से हमेशा ऐसा नहीं होता है।
mr.stobbe

15
double a_nan = strtod("NaN", NULL);
double a_inf = strtod("Inf", NULL);

4
यह एक स्मार्ट पोर्टेबल समाधान है! C99 के लिए strtodNaN और Inf का रूपांतरण करना आवश्यक है।
ulidtko

1
ऐसा नहीं है कि इस समाधान के साथ एक खामी है; वे निरंतर नहीं हैं। आप उदाहरण के लिए (या किसी सरणी को आरंभीकृत करने के लिए) एक वैश्विक चर को इनिशियलाइज़ करने के लिए इन मानों का उपयोग नहीं कर सकते।
मार्क

1
@Marc। आपके पास हमेशा एक शुरुआती फ़ंक्शन हो सकता है जो उन्हें एक बार कॉल करता है और उन्हें वैश्विक नामस्थान में सेट करता है। यह बहुत काम की कमी है।
मैड फिजिसिस्ट

3
<inf.h>

/* IEEE positive infinity.  */

#if __GNUC_PREREQ(3,3)
# define INFINITY   (__builtin_inff())
#else
# define INFINITY   HUGE_VALF
#endif

तथा

<bits/nan.h>
#ifndef _MATH_H
# error "Never use <bits/nan.h> directly; include <math.h> instead."
#endif


/* IEEE Not A Number.  */

#if __GNUC_PREREQ(3,3)

# define NAN    (__builtin_nanf (""))

#elif defined __GNUC__

# define NAN \
  (__extension__                                  \
   ((union { unsigned __l __attribute__ ((__mode__ (__SI__))); float __d; })  \
    { __l: 0x7fc00000UL }).__d)

#else

# include <endian.h>

# if __BYTE_ORDER == __BIG_ENDIAN
#  define __nan_bytes       { 0x7f, 0xc0, 0, 0 }
# endif
# if __BYTE_ORDER == __LITTLE_ENDIAN
#  define __nan_bytes       { 0, 0, 0xc0, 0x7f }
# endif

static union { unsigned char __c[4]; float __d; } __nan_union
    __attribute_used__ = { __nan_bytes };
# define NAN    (__nan_union.__d)

#endif  /* GCC.  */

0

मुझे भी आश्चर्य है कि ये समय स्थिरांक नहीं हैं। लेकिन मुझे लगता है कि आप इन निर्देशों को आसानी से बना सकते हैं बस एक ऐसे निर्देश को निष्पादित करके जो इस तरह के अमान्य परिणाम देता है। 0 से विभाजित, 0 का लॉग, 90 का टैन, उस थोड़े बात।


0

मैं आमतौर पर उपयोग करता हूं

#define INFINITY (1e999)

या

const double INFINITY = 1e999

जो कम से कम IEEE 754 संदर्भों में काम करता है क्योंकि उच्चतम प्रतिनिधित्व योग्य दोहरे मूल्य मोटे तौर पर है 1e3081e309के रूप में अच्छी तरह से, के रूप में अच्छी तरह से काम करेगा 1e99999, लेकिन तीन nines पर्याप्त और यादगार है। चूँकि यह या तो एक डबल शाब्दिक ( #defineमामले में) या वास्तविक Infमूल्य है, यह 128-बिट ("लंबी डबल") फ़्लोट्स का उपयोग करने पर भी अनंत रहेगा।


1
यह बहुत खतरनाक है, मेरी राय में। कल्पना करें कि कोई व्यक्ति आपके कोड को 20 या इतने वर्षों में 128 बिट फ़्लोट में स्थानांतरित करता है (आपका कोड अविश्वसनीय जटिल विकास के माध्यम से जाता है, जिसमें से कोई भी चरण जिसकी आप आज भविष्यवाणी करने में सक्षम थे)। अचानक, घातांक सीमा बहुत बढ़ जाती है, और आपके सभी 1e999शाब्दिक अब गोल नहीं होते हैं +Infinity। प्रति मर्फी के नियम, यह एक एल्गोरिथ्म को तोड़ता है। इससे भी बदतर: एक मानव प्रोग्रामर जो "128-बिट" बिल्ड कर रहा है, संभवतः उस त्रुटि को अग्रिम रूप से स्पॉट नहीं करेगा। Ie सबसे अधिक संभावना है कि यह त्रुटि और मान्यता प्राप्त होने पर बहुत देर हो जाएगी । बहूत खतरनाक।
ulidtko

1
बेशक, ऊपर सबसे खराब स्थिति यथार्थवादी से दूर हो सकती है। लेकिन फिर भी, विकल्पों पर विचार करें! सुरक्षित पक्ष पर रहना बेहतर है।
ulidtko

2
"20 साल में", हे। आओ। यह उत्तर उतना बुरा नहीं है
ऐलेकोव

@ulidtko मुझे यह पसंद नहीं है, लेकिन वास्तव में?
इरहब अल असिमी

0

यहाँ उन स्थिरांक को परिभाषित करने का एक सरल तरीका है, और मुझे पूरा यकीन है कि यह पोर्टेबल है:

const double inf = 1.0/0.0;
const double nan = 0.0/0.0;

जब मैं यह कोड चलाता हूं:

printf("inf  = %f\n", inf);
printf("-inf = %f\n", -inf);
printf("nan  = %f\n", nan);
printf("-nan = %f\n", -nan);

मुझे मिला:

inf  = inf
-inf = -inf
nan  = -nan
-nan = nan
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.