1.0 से निकटतम डबल क्या है, वह 1.0 नहीं है?


88

क्या प्रोग्राम को डबल करने का एक तरीका है जो 1.0 के सबसे करीब है, लेकिन वास्तव में 1.0 नहीं है?

ऐसा करने का एक आसान तरीका यह होगा कि डबल को एक ही आकार के पूर्णांक को याद रखें, और फिर एक को घटाएं। जिस तरह से IEEE754 फ़्लोटिंग-पॉइंट फॉरमेट काम करते हैं, यह सभी ज़ीरो (1.000000000000) से सभी (1.111111111111) तक के आंशिक भाग को बदलते समय प्रतिपादक को कम करके समाप्त कर देगा। हालाँकि ऐसी मशीनें मौजूद हैं जहाँ फ्लोटिंग-पॉइंट को बड़े-एंडियन संग्रहित करते समय पूर्णांक को थोड़ा-सा एंडियन संग्रहित किया जाता है, ताकि यह हमेशा काम न करे।


4
आप यह नहीं मान सकते कि +1 समान दूरी (1.0 से) -1 है। आधार 10 और बेस 2 फ़्लोटिंग पॉइंट अभ्यावेदन का इंटरलायिंग का मतलब है कि अंतराल असमान हैं।
रिचर्ड क्राइस्ट

2
@ रिचर्ड: आप सही कह रहे हैं। यह बहुत कम संभावना नहीं है कि एक ULP को घटाकर, "अगली पीढ़ी" मान प्राप्त होगा, क्योंकि मुझे लगता है कि घातांक को भी समायोजित करना होगा। nextafter()वह जो चाहता है उसे प्राप्त करने का एकमात्र उचित तरीका है।
रूडी वेल्थसुब

1
: FYI करें एक इस ब्लॉग (मेरा नहीं) के पढ़ा है exploringbinary.com/...
रिचर्ड Critten

1
@RudyVelthuis: यह हर IEEE754 बाइनरी फ्लोटिंग पॉइंट फॉर्मेट पर काम करता है।
एडगर बोनेट

1
ठीक है, तो मुझे बताओ: "प्रत्येक IEEE754 फ़्लोटिंग पॉइंट प्रारूप पर क्या काम करता है"? यह केवल सच नहीं है कि यदि आप उस महत्व को घटाते हैं जो आपको "फर्स्टब्रोफ ()" मूल्य मिलता है, विशेष रूप से 1.0 के लिए नहीं, जिसका एक महत्व है जो दो की शक्ति है। इसका मतलब है कि 1.0000...द्विआधारी में वृद्धि 0.111111....और इसे सामान्य करने के लिए, आपको इसे बाईं ओर स्थानांतरित करना होगा: 1.11111...जिसके लिए आपको घातांक को घटाना होगा। और फिर आप 1.0 से 2 ulp दूर हैं। तो नहीं, अभिन्न मूल्य से किसी को घटाना आपको यहां पर नहीं दिया जाता है।
रूडी वेल्थसुब

जवाबों:


23

C और C ++ में, निम्नलिखित 1.0 को निकटतम मान देता है:

#include <limits.h>

double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;

नोट करें कि C ++ के बाद के संस्करणों में, limits.hइसके पक्ष में पदावनत किया गया है climits। लेकिन फिर, यदि आप वैसे भी C ++ विशिष्ट कोड का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं

#include <limits>

typedef std::numeric_limits<double> lim_dbl;
double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;

और जैसा कि Jarod42 अपने जवाब में लिखते हैं, चूंकि C99 या C ++ 11 आप भी उपयोग कर सकते हैं nextafter:

#include <math.h>

double closest_to_1 = nextafter(1.0, 0.0);

C ++ में निश्चित रूप से (और बाद में C ++ संस्करणों के लिए) को शामिल करना चाहिए cmathऔर std::nextafterइसके बजाय उपयोग करना चाहिए ।


143

C ++ 11 के बाद से, आप nextafterदिए गए दिशा में अगला प्रतिनिधित्व मूल्य प्राप्त करने के लिए उपयोग कर सकते हैं :

std::nextafter(1., 0.); // 0.99999999999999989
std::nextafter(1., 2.); // 1.0000000000000002

डेमो


11
यह भी अगले प्रतिनिधित्व योग्य पूर्णांक के लिए एक डबल वृद्धि के लिए एक अच्छा तरीका है std::ceil(std::nextafter(1., std::numeric_limits<double>::max())):।
जोहान्स शाउब -

43
अगले सवाल "stdlib में इसे कैसे लागू किया जाता है": P
दौड़ ऑर्बिट में

17
@ LightnessRacesinOrbit की टिप्पणी पढ़ने के बाद मैं उत्सुक हो गया। यह है कि nextafterग्लिब कैसे लागू होता है , और यह है कि अगर यह किसी और को कैसे देखना चाहता है, तो यह मांसपेशियों को लागू करता है। असल में: कच्चे बिट twiddling।
कॉर्न्स्टल

2
@Cornstalks: मुझे आश्चर्य नहीं है कि यह बिट ट्विडलिंग के लिए नीचे है, केवल अन्य विकल्प में सीपीयू समर्थन होगा।
Matthieu M.

5
बिट टिडलिंग इसे ठीक से करने का एकमात्र तरीका है, IMO। आप बहुत सारे परीक्षण कर सकते हैं, धीरे-धीरे इसे प्राप्त करने की कोशिश कर रहे हैं, लेकिन यह बहुत धीमा हो सकता है।
रूडी वेल्थसुब

25

C में, आप इसका उपयोग कर सकते हैं:

#include <float.h>
...
double value = 1.0+DBL_EPSILON;

DBL_EPSILON 1 से 1 के बीच अंतर कम से कम मूल्य है जो कि प्रतिनिधित्व योग्य है।

वास्तविक मूल्य देखने के लिए आपको इसे कई अंकों में प्रिंट करना होगा।

मेरे मंच पर, printf("%.16lf",1.0+DBL_EPSILON)देता है 1.0000000000000002


10
ताकि डेमो के1. रूप में कुछ अन्य मूल्यों के लिए अभ्यस्त काम1'000'000
Jarod42

7
@ Jarod42: आप सही कह रहे हैं, लेकिन ओपी विशेष रूप से पूछता है 1.0। BTW, यह 1 से अधिक निकटतम मान भी देता है, न कि 1 का पूर्ण निकटतम मान (जो संभवतः 1 से छोटा है)। इसलिए मैं मानता हूं कि यह एक आंशिक जवाब है, लेकिन मुझे लगा कि यह फिर भी योगदान दे सकता है।
बराक मानोस

@ LưuV LnhPhúc: मैं उत्तर के प्रतिबंध, और दूसरी दिशा में निकटतम के बारे में सटीक जानकारी देता हूं।
Jarod42

7
यह निकटतम डबल को 1.0 नहीं देता है , जैसा कि (आधार 2 को मानकर) 1.0 से पहले डबल राइट केवल 1.0 के बाद डबल राइट के रूप में केवल आधा है (जो आप गणना करते हैं)।
celtschk

@celtschk: आप सही कह रहे हैं, मैंने ऊपर टिप्पणी में बताया है।
बराक मानस

4

C ++ में आप इसका भी उपयोग कर सकते हैं

1 + std::numeric_limits<double>::epsilon()

1
बराक मानोस के जवाब की तरह, यह किसी भी मूल्य के अलावा 1 के लिए काम नहीं करेगा
zwol

2
@zwol ठेठ बाइनरी फ़्लोटिंग पॉइंट कार्यान्वयन के लिए तेहनीली यह 1 और 2-एप्सिलॉन के बीच किसी भी मूल्य के लिए काम करेगा। लेकिन, हाँ, आप सही कह रहे हैं कि यह केवल 21 पर लागू होने की गारंटी है।
random832

7
तकनीकी रूप से, यह 1 के लिए काम नहीं करता है, क्योंकि 1 से निकटतम संख्या 1 से ठीक पहले की संख्या है, न कि इसके ठीक बाद की। 0.5 और 1 के बीच की दोहरी सटीकता 1 और 2 के बीच इसकी सटीकता से दोगुनी है, इसलिए 1 से ठीक पहले संख्या 1 के करीब समाप्त होती है
हैलोगौडेबी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.