নির্ভুলতা না হারিয়ে ফ্লোটকে দ্বিগুণ রূপান্তর করুন


98

আমার একটি আদিম ভাসা আছে এবং আমার একটি আদিম দ্বৈত হিসাবে প্রয়োজন। কেবল দ্বৈতভাবে ফ্লোটটি castালাই আমাকে অদ্ভুত অতিরিক্ত স্পষ্টতা দেয়। উদাহরণ স্বরূপ:

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এটি একটি আরও উপযুক্ত টাইপ আইএমও।


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), যা অংশে বলেছে:

ভগ্নাংশের জন্য কতগুলি অঙ্ক মুদ্রিত করতে হবে […]? ভগ্নাংশের অংশকে উপস্থাপন করার জন্য কমপক্ষে একটি অঙ্ক থাকতে হবে এবং এর বাইরেও অনেকগুলি, তবে কেবলমাত্র আরও অনেকগুলি সংখ্যা যেমন ভাসমানের সংলগ্ন মানগুলির সাথে যুক্তির মানটিকে স্বতন্ত্রভাবে আলাদা করতে প্রয়োজন। অর্থাত্, ধরুন যে এক্স একটি সীমাবদ্ধ ননজারো আর্গুমেন্টের জন্য এই পদ্ধতির দ্বারা উত্পাদিত দশমিক প্রতিনিধিত্ব করে সঠিক গাণিতিক মান value তারপরে চ অবশ্যই এক্স এর নিকটতম ভাসমান মান হতে হবে; অথবা, যদি দুটি ফ্লোট মানগুলি সমানভাবে এক্স এর কাছাকাছি থাকে, তবে চ অবশ্যই তাদের মধ্যে একটি হতে হবে এবং এফ এর তাত্পর্যপূর্ণতার সর্বনিম্ন উল্লেখযোগ্য বিট অবশ্যই 0 হওয়া উচিত।


13

আমি আজ এই সমস্যার মুখোমুখি হয়েছি এবং বিগডিসিমালে রিফ্যাক্টর ব্যবহার করতে পারিনি, কারণ প্রকল্পটি আসলেই বিশাল। তবে আমি ব্যবহার করে সমাধান পেয়েছি

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

এবং এই কাজ করে।

নোট করুন যে কলিং রেজাল্ট.ডুবলভ্যালু () 5623.22998046875 প্রদান করে

কিন্তু ডাবল রিসালট ডাবলভ্যালু () কল করলে 5623.23 সঠিকভাবে ফিরে আসে

তবে আমি এর সঠিক সমাধান কিনা তা সম্পর্কে আমি পুরোপুরি নিশ্চিত নই।


4
আমার জন্য কাজ করেছেন। খুব দ্রুত। কেন এটি উত্তর হিসাবে চিহ্নিত হয়নি তা নিশ্চিত নয়।
সমীর

এই পদ্ধতিটি আমি ব্যবহার করি এবং আপনার নতুন ফ্লোট অংশের দরকার নেই ... আদিম দিয়ে স্রেফ ফ্লোটিংডেসিমাল তৈরি করুন। এটি স্বয়ংক্রিয়ভাবে বক্স হয়ে যাবে ... এবং দ্রুত কাজ করে ... সেখানে রয়েছে; ওয়াই একটি ত্রুটি, ফ্লোটিংডিসিমাল অপরিবর্তনীয়, সুতরাং আপনাকে প্রতিটি একক ভাসনের জন্য একটি তৈরি করতে হবে ... হে (1e10) এর একটি গণনার কোডটি কল্পনা করুন! !! অবশ্যই বিগডিসিমেলের একই অপূর্ণতা রয়েছে ...
মোস্তফা জিনালি

6
এই সমাধানটির অপূর্ণতা হ'ল সান.মিস্ক.ফ্লোটিংডিসিমাল হল জেভিএমের অভ্যন্তরীণ শ্রেণি এবং জাভা ১.৮ এ এর ​​নির্মাতার স্বাক্ষর পরিবর্তন করা হয়েছে। বাস্তব জীবনের আবেদনে নুনের অভ্যন্তরীণ ক্লাস ব্যবহার করা উচিত নয়।
ইগোর ব্লজাহিন

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পরিবর্তে একটি ব্যবহার করুন । প্রচুর সংখ্যা রয়েছে যা বাইনারি ভাসমান পয়েন্ট হিসাবে প্রতিনিধিত্ব করা যায় না (উদাহরণস্বরূপ )। সুতরাং আপনি হয় সর্বদা একটি পরিচিত নির্ভুলতা বা ব্যবহারের ফলাফল অবশ্যই গোল করতে হবে ।floatdouble0.1BigDecimal

আরও তথ্যের জন্য http://en.wikedia.org/wiki/Floating_Point দেখুন ।


বলুন যে আপনার ক্যাশে আপনার 10 মি ফ্লোট ব্যবসায়ের মূল্য রয়েছে, আপনি কি এখনও বিগডিসিমাল ব্যবহার করে বিবেচনা করেন এবং অনন্য তাত্ক্ষণিকভাবে m 6m অবজেক্টকে (ফ্লাইওয়েট / অপরিবর্তনীয় ছাড়) বলতে চান .. বা এর থেকেও আরও কিছু আছে?
সেন্ডি_টি

4
@ সেন্ডি_টি দয়া করে জটিল প্রশ্ন জিজ্ঞাসা করার জন্য মন্তব্যগুলি ব্যবহার করবেন না :-)
অ্যারন ডিগুল্লা

দেখার জন্য ধন্যবাদ! .. আমরা এক দশক আগে যেমন সম্মত হয়েছিল ঠিক তেমনই এখনই ফ্লোট ব্যবহার করি - আমি এই পরিস্থিতি সম্পর্কে আপনার দৃষ্টিভঙ্গি অনুসরণের চেষ্টা করার চেষ্টা করছিলাম -। ধন্যবাদ!
সেন্ডি_টি

@ সেন্টি_টি ভুল বোঝাবুঝি আমি 512 টি অক্ষরে আপনার প্রশ্নের উত্তর দিতে পারি না। দয়া করে একটি উপযুক্ত প্রশ্ন জিজ্ঞাসা করুন এবং আমাকে একটি লিঙ্ক প্রেরণ করুন।
অ্যারন ডিজুল্লা

4
@GKFX কম্পিউটারে দশমিকগুলি পরিচালনা করার ক্ষেত্রে কোনও "এক আকার সবই ফিট করে না"। তবে যেহেতু বেশিরভাগ লোকেরা এটি পায় না, তাই আমি তাদের দিকে লক্ষ্য করি BigDecimalযেহেতু এটি বেশিরভাগ সাধারণ ত্রুটিটি ধরবে catch যদি জিনিসগুলি খুব ধীর হয় তবে তাদের আরও শিখতে হবে এবং তাদের সমস্যাগুলি অনুকূল করার উপায় খুঁজে বের করতে হবে। অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূলে - ডি নাথ।
অ্যারন দিগুল্লা

1

প্রকৃতির দ্বারা ভাসমানগুলি অস্পষ্ট এবং সর্বদা ঝরঝরে "ইস্যুগুলি" রাখে। যথার্থতা যদি গুরুত্বপূর্ণ হয় তবে আপনি দশমিক বা বিগডিসিমাল ব্যবহারের জন্য আপনার অ্যাপ্লিকেশনটিকে রিফ্যাক্টর করার বিষয়টি বিবেচনা করতে পারেন।

হ্যাঁ, অন প্রসেসরের সহায়তার কারণে ফ্লোটগুলি দশমিকের চেয়ে কমপিটেশনালভাবে দ্রুত are তবে, আপনি দ্রুত বা সঠিক চান?


4
দশমিক গাণিতিকটিও নির্ভুল। (যেমন 1/3 * 3 == 0.999999999999999999999999999999) অর্থের মতো সঠিক দশমিক পরিমাণ উপস্থাপনের জন্য এটি অবশ্যই ভাল তবে শারীরিক পরিমাপের জন্য এর কোনও সুবিধা নেই।
dan04

4
তবে 1 == 0.9999999999999999999999999999 :)
এমানুয়েল

0

তথ্যের জন্য এটি আইটেম 48 এর আওতায় আসে - জোশুয়া ব্লচের কার্যকর জাভা 2 য় সংস্করণটির যথাযথ মান প্রয়োজন হলে ভাসা এবং দ্বিগুণ এড়ানো। এই বইটি ভাল স্টাফ দিয়ে প্যাকড জ্যাম এবং অবশ্যই দেখার জন্য মূল্যবান।



0

একটি সহজ সমাধান যা ভালভাবে কাজ করে তা হ'ল ফ্লোটের স্ট্রিং প্রতিনিধিত্ব থেকে ডাবলকে পার্স করা:

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

সুপার দক্ষ নয়, তবে এটি কার্যকর!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.