सटीक खोए बिना फ्लोट को डबल में बदलें


97

मेरे पास एक आदिम फ्लोट है और मुझे एक आदिम डबल के रूप में आवश्यकता है। बस फ्लोट को डबल करने के लिए मुझे अजीब अतिरिक्त परिशुद्धता देता है। उदाहरण के लिए:

float temp = 14009.35F;
System.out.println(Float.toString(temp)); // Prints 14009.35
System.out.println(Double.toString((double)temp)); // Prints 14009.349609375

हालांकि, अगर कास्टिंग के बजाय, मैं फ्लोट को एक स्ट्रिंग के रूप में आउटपुट करता हूं, और स्ट्रिंग को डबल के रूप में पार्स करता हूं, मुझे वह मिलता है जो मुझे चाहिए:

System.out.println(Double.toString(Double.parseDouble(Float.toString(temp))));
// Prints 14009.35

क्या स्ट्रिंग और वापस जाने की तुलना में बेहतर तरीका है?

जवाबों:


125

ऐसा नहीं है कि आप वास्तव में अतिरिक्त सटीकता प्राप्त कर रहे हैं - यह है कि फ्लोट उस संख्या का सही प्रतिनिधित्व नहीं करता है जिसे आप मूल रूप से लक्ष्य कर रहे थे। डबल है मूल नाव सही रूप का प्रतिनिधित्व; toString"अतिरिक्त" डेटा दिखा रहा है जो पहले से मौजूद था।

उदाहरण के लिए (और ये संख्या सही नहीं है, मैं सिर्फ बातें बना रहा हूं) मान लीजिए कि आपके पास था:

float f = 0.1F;
double d = f;

तब इसका मूल्य fठीक 0.100000234523 हो सकता है। dइसका ठीक वैसा ही मूल्य होगा, लेकिन जब आप इसे एक स्ट्रिंग में बदलेंगे तो यह "विश्वास" होगा कि यह एक उच्च परिशुद्धता के लिए सटीक है, इसलिए यह जल्दी से गोल नहीं होगा, और आप "अतिरिक्त अंक" देखेंगे जो पहले से ही थे वहाँ, लेकिन आप से छिपा हुआ।

जब आप एक स्ट्रिंग और बैक में कनवर्ट करते हैं, तो आप एक डबल मान के साथ समाप्त कर रहे हैं, जो मूल फ्लोट की तुलना में स्ट्रिंग मान के करीब है - लेकिन यह केवल अच्छा है यदि आप वास्तव में विश्वास करते हैं कि स्ट्रिंग मूल्य वह है जो आप वास्तव में चाहते थे।

क्या आप सुनिश्चित हैं कि फ़्लोट / डबल इसके बजाय यहाँ उपयोग करने के लिए उपयुक्त प्रकार हैं BigDecimal? यदि आप उन संख्याओं का उपयोग करने का प्रयास कर रहे हैं जिनमें सटीक दशमलव मान (जैसे धन) हैं, तो BigDecimalएक अधिक उपयुक्त प्रकार IMO है।


40

मैं इस समस्या को समझने के लिए बाइनरी प्रतिनिधित्व को आसान बनाता हूं।

float f = 0.27f;
double d2 = (double) f;
double d3 = 0.27d;

System.out.println(Integer.toBinaryString(Float.floatToRawIntBits(f)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d2)));
System.out.println(Long.toBinaryString(Double.doubleToRawLongBits(d3)));

आप देख सकते हैं कि फ्लोट को 0 से अंत तक जोड़कर डबल तक विस्तारित किया गया है, लेकिन 0.27 का डबल प्रतिनिधित्व 'अधिक सटीक' है, इसलिए समस्या है।

   111110100010100011110101110001
11111111010001010001111010111000100000000000000000000000000000
11111111010001010001111010111000010100011110101110000101001000

25

यह अनुबंध के कारण है Float.toString(float), जो कहता है:

आंशिक भाग […] के लिए कितने अंक छपे होने चाहिए? भिन्नात्मक भाग का प्रतिनिधित्व करने के लिए कम से कम एक अंक होना चाहिए, और उससे आगे भी, लेकिन केवल कई, अधिक अंकों के रूप में विशिष्ट प्रकार के फ्लोट के आसन्न मूल्यों से तर्क मूल्य को अलग करने की आवश्यकता होती है। यही है, मान लीजिए कि x एक परिमित गैर-बीजरूप तर्क f के लिए इस विधि द्वारा निर्मित दशमलव प्रतिनिधित्व द्वारा दर्शाया गया सटीक गणितीय मान है। तब f को x के निकटतम फ्लोट मान होना चाहिए; या, यदि दो फ्लोट मान समान रूप से x के करीब हैं, तो f उनमें से एक होना चाहिए और f के महत्व का कम से कम महत्वपूर्ण बिट 0 होना चाहिए।


13

मैं आज इस मुद्दे का सामना कर चुका हूं और बिगडेसीमल के लिए रिफ्लेक्टर का उपयोग नहीं कर सकता, क्योंकि परियोजना वास्तव में बहुत बड़ी है। हालांकि मैंने समाधान का उपयोग कर पाया

Float result = new Float(5623.23)
Double doubleResult = new FloatingDecimal(result.floatValue()).doubleValue()

और यह काम करता है।

ध्यान दें कि call.doubleValue () 5623.22998046875 पर कॉल करता है

लेकिन doubleResult.doubleValue () कॉलिंग सही ढंग से 5623.23 पर वापस आती है

लेकिन मुझे पूरी तरह यकीन नहीं है कि इसका सही समाधान है।


1
मेरे लिए काम किया। भी बहुत तेज है। निश्चित नहीं है कि यह उत्तर के रूप में चिह्नित क्यों नहीं है।
समीर

यह मेरे द्वारा उपयोग की जाने वाली विधि है, और आपको नए फ़्लोट भाग की आवश्यकता नहीं है ... बस आदिम के साथ फ़्लोटिंगडेसिमल बनाएं। यह स्वचालित रूप से बॉक्सिंग किया जाएगा ... और तेजी से भी काम करता है ... वहाँ एक वाई है, फ़्लोटिंगडेसिमल अपरिवर्तनीय है, इसलिए यू को हर एक फ्लोट के लिए एक बनाने की आवश्यकता है ... ओ (1e10) के कम्प्यूटेशनल कोड की कल्पना करें! !! बेशक BigDecimal में एक ही खामी है ...
Mostafa Zeinali

6
इस समाधान का दोष यह है कि sun.misc.FloatingDecimal JVM का आंतरिक वर्ग है और इसके निर्माता के हस्ताक्षर जावा 1.8 में बदल दिए गए हैं। किसी को वास्तविक जीवन के आवेदन में आंतरिक कक्षाओं का उपयोग नहीं करना चाहिए।
इगोर ब्लाजहिन

8

मुझे निम्नलिखित समाधान मिला:

public static Double getFloatAsDouble(Float fValue) {
    return Double.valueOf(fValue.toString());
}

यदि आप का उपयोग नाव और दोगुना करने के बजाय फ्लोट और डबल निम्नलिखित का उपयोग करें:

public static double getFloatAsDouble(float value) {
    return Double.valueOf(Float.valueOf(value).toString()).doubleValue();
}

7

के BigDecimalबजाय का उपयोग करें float/ double। बहुत सारी संख्याएँ हैं जिन्हें बाइनरी फ़्लोटिंग पॉइंट (उदाहरण के लिए 0.1) के रूप में प्रस्तुत नहीं किया जा सकता है । इसलिए आपको या तो हमेशा परिणाम को ज्ञात सटीकता या उपयोग के लिए गोल करना चाहिए BigDecimal

अधिक जानकारी के लिए http://en.wikipedia.org/wiki/Floating_point देखें ।


कहते हैं कि आपके कैश में 10 मीटर फ्लोट व्यापार की कीमतें हैं, क्या आप अभी भी BigDecimal का उपयोग करने पर विचार करते हैं और तत्काल अद्वितीय कहते हैं ~ 6m ऑब्जेक्ट्स (फ्लाईवेट / अपरिवर्तनीय छूट देने के लिए) .. या इसमें और भी बहुत कुछ है?
सेंडी_टी

1
@Sendi_t कृपया जटिल प्रश्न पूछने के लिए टिप्पणियों का उपयोग न करें :-)
हारून डिगुल्ला

तलाश के लिए धन्यवाद! .. हम अभी फ़्लोट्स का उपयोग करते हैं, जैसा कि एक दशक पहले सहमति हुई थी - मैं इस स्थिति पर आपके दृष्टिकोण को देखने की कोशिश कर रहा था -। धन्यवाद!
सेंडी_टी

@Sendi_t गलतफहमी। मैं 512 वर्णों में आपके प्रश्न का उत्तर नहीं दे सकता। कृपया एक उचित प्रश्न पूछें और मुझे एक लिंक भेजें।
आरोन दिगुल्ला

1
@GKFX कोई "एक आकार सभी फिट बैठता है" जब यह कंप्यूटर पर दशमलव को संभालने के लिए आता है। लेकिन चूंकि अधिकांश लोग इसे प्राप्त नहीं करते हैं, मैं उन्हें इंगित करता हूं BigDecimalक्योंकि यह सबसे आम त्रुटियों को पकड़ लेगा। यदि चीजें बहुत धीमी हैं, तो उन्हें और अधिक सीखने और अपनी समस्याओं को अनुकूलित करने के तरीके खोजने की आवश्यकता है। समयपूर्व अनुकूलन सभी बुराई की जड़ है - DE Knuth।
आरोन दिगुल्ला

1

स्वभाव से झांकियां, अभेद्य होती हैं और इनमें हमेशा "गोल" वाले गोल होते हैं। यदि परिशुद्धता महत्वपूर्ण है, तो आप दशमलव या बिगडिमल का उपयोग करने के लिए अपने आवेदन को वापस लेने पर विचार कर सकते हैं।

हां, प्रोसेसर सपोर्ट की वजह से फ्लोट कम्प्यूटेशनल रूप से डेसीमल से ज्यादा तेज हैं। हालाँकि, क्या आप तेज या सटीक चाहते हैं?


1
दशमलव अंकगणित भी अक्षम है। (जैसे 1/3 * 3 == 0.999999999999999999999999999999) यह निश्चित रूप से, पैसे की तरह सटीक दशमलव मात्रा का प्रतिनिधित्व करने के लिए बेहतर है, लेकिन भौतिक माप के लिए इसका कोई फायदा नहीं है।
dan04

2
लेकिन 1 == 0.9999999999999999999999999999 :)
Emmanuel Bourg

0

यह जानकारी 48 आइटम के अंतर्गत आती है - जोशुआ बलोच द्वारा प्रभावी जावा 2 संस्करण के सटीक मूल्यों की आवश्यकता होने पर फ्लोट और डबल से बचें। यह पुस्तक अच्छी चीजों से भरी हुई है और निश्चित रूप से देखने लायक है।


0

क्या यह काम करता है?

float flt = 145.664454;

Double dbl = 0.0;
dbl += flt;

0

एक सरल समाधान जो अच्छी तरह से काम करता है, वह है फ्लोट के स्ट्रिंग प्रतिनिधित्व से डबल पार्स करना:

double val = Double.valueOf(String.valueOf(yourFloat));

सुपर कुशल नहीं है, लेकिन यह काम करता है!

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