ভাসমান-পয়েন্ট মানের যথার্থতা বজায় রাখতে প্রিন্টফ প্রস্থের নির্দিষ্টকরণকারী


103

সেখানে একটি হল printfপ্রস্থ সুনির্দিষ্টভাবে উল্লেখ করা যা ফ্লোটিং পয়েন্ট সুনির্দিষ্টভাবে উল্লেখ করা যা স্বয়ংক্রিয়ভাবে প্রয়োজনীয় সংখ্যক আউটপুট ফরম্যাট হবে প্রয়োগ করা যেতে পারে এতগুলি অর্থপূর্ণ অঙ্ক যেমন যে যখন স্ট্রিং ফিরে স্ক্যান, মূল ফ্লোটিং পয়েন্ট মান অর্জিত হয়?

উদাহরণস্বরূপ, ধরুন আমি দশমিক জায়গাগুলির floatযথার্থতার জন্য একটি মুদ্রণ করেছি 2:

float foobar = 0.9375;
printf("%.2f", foobar);    // prints out 0.94

আমি যখন আউটপুটটি স্ক্যান করি তখন আমার 0.94কোনও মান-সম্মতিযুক্ত গ্যারান্টি নেই যে আমি আসল 0.9375ভাসমান-পয়েন্ট মানটি ফিরে পাব (এই উদাহরণস্বরূপ, আমি সম্ভবত করব না)।

আমি একটি পথ বাতলে চাই printfস্বয়ংক্রিয়ভাবে প্রয়োজনীয় নম্বরে ফ্লোটিং পয়েন্ট মান প্রিন্ট করতে এতগুলি অর্থপূর্ণ অঙ্ক তা নিশ্চিত করতে মূল মান প্রেরণ ফিরে স্ক্যান করা যাবে printf

আমি ম্যাক্রো কিছু ব্যবহার করতে পারে float.hথেকে সর্বোচ্চ প্রস্থ আহরণ করতে পাস printf, কিন্তু তার আগেই একটা সুনির্দিষ্টভাবে উল্লেখ করা স্বয়ংক্রিয়ভাবে প্রয়োজনীয় সংখ্যক মুদ্রণ হয় এতগুলি অর্থপূর্ণ অঙ্ক - অথবা অন্তত সর্বোচ্চ প্রস্থ কিভাবে?


4
@ বোবোবোবু তাই আপনি কেবল সুপারিশ করছেন যে কেউ বহনযোগ্য দৃষ্টিভঙ্গি গ্রহণের পরিবর্তে বাতাসের বাইরে একটি অনুমান ব্যবহার করে?

1
@ H2CO3 না, আমি "বায়ু থেকে একটি অনুমিতি" ব্যবহার করার পরামর্শ দেব না, আমি printf( "%f", val );ইতিমধ্যে বহনযোগ্য, দক্ষ এবং ডিফল্ট ব্যবহার করার পরামর্শ দেব ।
বোবোবোবো

2
@ ববোব্বো যাতে আমি এটির উত্তরগুলিতে যুক্ত করতে পারি, আপনি কি C99 স্ট্যান্ডার্ডে এই ধারাটি উদ্ধৃত করতে সক্ষম হবেন যা বলে যে প্রিন্টফ স্টেটমেন্টটি সুনির্দিষ্টতার সাথে নির্দিষ্ট না হলে ডিফল্টভাবে সর্বাধিক নির্ভুলতায় ফ্লোট ধরণের আউটপুট দেবে ?
ভিলহেলম গ্রে

1
@ ভিলহেলগ্রে ওয়েল @ চ্যাক্স প্রবেশের সাথে সাথে আপনার বিশেষের যথার্থ নির্ভুলতার জন্য কিছু জটিল জটিল গণিত রয়েছে double। আপনার doubleচূড়ান্তভাবে বড় হওয়ার সাথে সাথে ( দশমিক অংশ থেকে খুব দূরে), এটি আসলে দশমিক অংশে (কম অংশের মান অংশের চেয়ে কম) সঠিকভাবে পায় । সুতরাং আপনার এখানে সত্যিই সন্তোষজনক উত্তর থাকতে পারে না, কারণ আপনার প্রশ্নের এতে একটি ভুল ধারণা রয়েছে (যথা সমস্ত floats / doubles সমানভাবে তৈরি করা হয়েছে)
বোবোবো

2
@ উইলহেলম গ্রে সি 11dr 5.2.4.2.2 "... দশমিক অঙ্কের সংখ্যা, এন, যেমন পি মূলত বি অঙ্কের সাথে যে কোনও ভাসমান-পয়েন্ট সংখ্যাটি এন দশমিক অঙ্ক সহ একটি ভাসমান-পয়েন্ট সংখ্যাটিকে গোল করে আবার কোনও পরিবর্তন ছাড়াই ফিরে যেতে পারে n মানটির জন্য, পি লগ 10 বিবি হ'ল 10 p1 + পি লগ 10 বিটির শক্তি অন্যথায় FLT_DECIMAL_DIG 6 ডিবিএল_ডিসিমাল_ডিজ 10 এলডিবিএল_ডিসিমাল_ডিজ 10 ... "6,10,10 সর্বনিম্ন মান।
chux - মনিকা

উত্তর:


92

আমি @ জেনস গুস্টেড হেক্সাডেসিমাল সলিউশনটি সুপারিশ করছি:% এ ব্যবহার করুন।

ওপি "সর্বাধিক নির্ভুলতার সাথে মুদ্রণ চায় (বা কমপক্ষে সর্বাধিক গুরুত্বপূর্ণ দশমিক)"।

একটি সাধারণ উদাহরণটি হ'ল এক সপ্তম হিসাবে নিম্নরূপ:

#include <float.h>
int Digs = DECIMAL_DIG;
double OneSeventh = 1.0/7.0;
printf("%.*e\n", Digs, OneSeventh);
// 1.428571428571428492127e-01

তবে আরও গভীর খনন করা যাক ...

গাণিতিকভাবে, উত্তরটি "0.142857 142857 142857 ...", তবে আমরা সসীম নির্ভুলতা ভাসমান পয়েন্ট সংখ্যা ব্যবহার করছি। আসুন আইইইই 754 ডাবল-স্পষ্টতা বাইনারি ধরে নিই । সুতরাং OneSeventh = 1.0/7.0নীচের মান ফলাফল। পূর্ববর্তী এবং নিম্নলিখিত প্রতিনিধিত্বমূলক doubleভাসমান পয়েন্ট সংখ্যাগুলিও দেখানো হয়েছে ।

OneSeventh before = 0.1428571428571428 214571170656199683435261249542236328125
OneSeventh        = 0.1428571428571428 49212692681248881854116916656494140625
OneSeventh after  = 0.1428571428571428 769682682968777953647077083587646484375

মুদ্রণ সঠিক একটি এর দশমিক উপস্থাপনা doubleসীমাবদ্ধ রয়েছে ব্যবহারসমূহ।

<float.h>আমাদের সহায়তায় সিতে 2 টি ম্যাক্রো পরিবার রয়েছে ।
প্রথম সেটটি দশমিক একটি স্ট্রিংয়ে মুদ্রণের জন্য উল্লেখযোগ্য অঙ্কের সংখ্যা তাই স্ট্রিংটি পিছনে স্ক্যান করার সময় আমরা আসল ভাসমান পয়েন্টটি পাই। সি স্পেকের সর্বনিম্ন মান এবং একটি নমুনা সি 11 সংকলক সহ দেখানো হয়েছে ।

FLT_DECIMAL_DIG   6,  9 (float)                           (C11)
DBL_DECIMAL_DIG  10, 17 (double)                          (C11)
LDBL_DECIMAL_DIG 10, 21 (long double)                     (C11)
DECIMAL_DIG      10, 21 (widest supported floating type)  (C99)

দ্বিতীয় সেটটি এমন একটি উল্লেখযোগ্য অঙ্কের সংখ্যা যা কোনও স্ট্রিং কোনও ভাসমান বিন্দুতে স্ক্যান হতে পারে এবং তারপরেও এফপি মুদ্রিত হয়, এখনও একই স্ট্রিং উপস্থাপনাটি ধরে রাখে। সি স্পেকের সর্বনিম্ন মান এবং একটি নমুনা সি 11 সংকলক সহ দেখানো হয়েছে । আমি বিশ্বাস করি প্রাক-সি 99 উপলব্ধ।

FLT_DIG   6, 6 (float)
DBL_DIG  10, 15 (double)
LDBL_DIG 10, 18 (long double)

ম্যাক্রোগুলির প্রথম সেটটি উল্লেখযোগ্য সংখ্যার ওপির লক্ষ্য পূরণ করে । তবে সেই ম্যাক্রো সবসময় পাওয়া যায় না।

#ifdef DBL_DECIMAL_DIG
  #define OP_DBL_Digs (DBL_DECIMAL_DIG)
#else  
  #ifdef DECIMAL_DIG
    #define OP_DBL_Digs (DECIMAL_DIG)
  #else  
    #define OP_DBL_Digs (DBL_DIG + 3)
  #endif
#endif

"+ 3" হ'ল আমার আগের উত্তরের ক্রুস। এটি কেন্দ্র করে যদি রাউন্ড-ট্রিপ রূপান্তর স্ট্রিং-এফপি-স্ট্রিং (সেট # 2 ম্যাক্রো উপলব্ধ সি 89) জেনে থাকে তবে কীভাবে কেউ এফপি-স্ট্রিং-এফপি (সেট # 1 ম্যাক্রো পোস্ট সি 89 পোস্ট করে) এর জন্য ডিজিট নির্ধারণ করবেন? সাধারণভাবে, 3 যোগ ফলাফল ছিল।

এখন কত গুরুত্বপূর্ণ মুদ্রণের ডিজিটের পরিচিত এবং মাধ্যমে চালিত হয় <float.h>

এন উল্লেখযোগ্য দশমিক অঙ্ক মুদ্রণের জন্য কেউ বিভিন্ন ফর্ম্যাট ব্যবহার করতে পারে।

সহ "%e", যথার্থ ক্ষেত্রটি সীসা অঙ্ক এবং দশমিক বিন্দুর পরে অঙ্কের সংখ্যা । যাতে - 1আদেশ হয়। দ্রষ্টব্য: এটি -1প্রাথমিক নয়int Digs = DECIMAL_DIG;

printf("%.*e\n", OP_DBL_Digs - 1, OneSeventh);
// 1.4285714285714285e-01

সাথে "%f", যথার্থ ক্ষেত্র হ'ল দশমিক বিন্দুর পরে অঙ্কের সংখ্যা । মত একটি সংখ্যা জন্য OneSeventh/1000000.0, এক হবে OP_DBL_Digs + 6সব দেখতে উল্লেখযোগ্য সংখ্যার।

printf("%.*f\n", OP_DBL_Digs    , OneSeventh);
// 0.14285714285714285
printf("%.*f\n", OP_DBL_Digs + 6, OneSeventh/1000000.0);
// 0.00000014285714285714285

দ্রষ্টব্য: অনেকেই অভ্যস্ত "%f"। যে দশমিক বিন্দু পরে 6 ডিজিট প্রদর্শন করে; 6 হ'ল ডিসপ্লে ডিফল্ট, সংখ্যার যথার্থতা নয়।


কেন 1.428571428571428492127e-01 এবং 1.428571428571428492127e-0 0 1 নয়, 'ই' এর পরে অঙ্কের সংখ্যা 3 হওয়া উচিত?
ব্যবহারকারী 1024

12.12.5 ফ্লোটিং-পয়েন্ট রূপান্তরগুলি বলছে যে এর জন্য পূর্বনির্ধারিত নির্ভুলতা %f6
gu

1
@ জিংগুও ইয়াও সম্মত হন যে রেফারেন্সে বলা হয়েছে যে "নির্ভুলতা উল্লেখ করে যে '% f'" এর জন্য দশমিক-পয়েন্টের অক্ষরটি কত সংখ্যার অনুসরণ করে "The "সুস্পষ্টতা" শব্দটি গাণিতিক অর্থে ব্যবহৃত হয় না , তবে কেবল দশমিক বিন্দুর পরে অঙ্কের সংখ্যার জন্য সংজ্ঞা দিতে হয়। 1234567890.123, গাণিতিকভাবে 13 অঙ্ক বা যথাযথ সংখ্যা রয়েছে digit 0,000000000123 গাণিতিক নির্ভুলতা 3 সংখ্যা আছে, না 13. ফ্লোটিং পয়েন্ট সংখ্যা logarithmically distributed.This উত্তর ব্যবহার হয় উল্লেখযোগ্য সংখ্যার এবং গাণিতিক অর্থে স্পষ্টতা
chux - মনিকা পুনরায় ইনস্টল করুন

1
@ স্লিপ ডি থম্পসন "সেখানে সি স্পেকের ন্যূনতম মান এবং একটি নমুনা সি 11 সংকলক সহ দেখানো হয়েছে ।"
chux - মনিকা

1
প্রকৃতপক্ষে আপনি সঠিক - আমার ট্রিকটি কেবলমাত্র 1.0 এবং 1.0eDBL_DIG এর মধ্যে একটি মাত্রার মানগুলির জন্য বৈধ, যা "%f"প্রথম স্থানে মুদ্রণের জন্য সত্যই উপযুক্ত একমাত্র পরিসীমা । ব্যবহার "%e"হিসাবে আপনি দেখিয়েছেন হয় অবশ্যই আরো ভালো সব বৃত্তাকার এবং কার্যকরভাবে একটি শালীন উত্তর (যদিও সম্ভবত এটি ব্যবহার হিসাবে ভাল হিসাবে নয় কাছে "%a"যদি এটি পাওয়া যায় হতে পারে, এবং অবশ্যই "%a"পাওয়া উচিত যদি `DBL_DECIMAL_DIG যায়)। আমি সর্বদা সুনির্দিষ্ট নির্ভুলতার (হার্ড-কোডিং dec দশমিক স্থানের পরিবর্তে) সর্বদা সুনির্দিষ্ট করে ফর্ম্যাট স্পেসিফায়ারের জন্য চেয়েছিলাম।
গ্রেগ এ উডস

66

ভাসমান বিন্দু সংখ্যা নিখরচায় মুদ্রণের সংক্ষিপ্ত উত্তর (যেমন এগুলি এনএএন এবং ইনফিনিটি বাদে ঠিক একই সংখ্যায় আবার পড়তে পারে):

  • যদি আপনার টাইপটি ভাসমান থাকে: ব্যবহার করুন printf("%.9g", number)
  • যদি আপনার টাইপ দ্বিগুণ হয়: ব্যবহার করুন printf("%.17g", number)

ব্যবহার করবেন না %f, যেহেতু এটি কেবলমাত্র দশমিকের পরে কতগুলি উল্লেখযোগ্য সংখ্যা নির্দিষ্ট করে এবং ছোট সংখ্যাকে কাটাবে। রেফারেন্সের জন্য, 9 এবং 17 নম্বর জাদুটি পাওয়া যাবে float.hযা সংজ্ঞা দেয় FLT_DECIMAL_DIGএবং DBL_DECIMAL_DIG


6
আপনি কি %gস্পেসিফায়ারকে ব্যাখ্যা করতে সক্ষম হবেন ?
ভিলহেলম গ্রে

14
% জি সংক্ষিপ্ততার জন্য প্রয়োজনীয় যতগুলি সংখ্যা সহ প্রিন্ট করে, সংখ্যাগুলি যখন ছোট বা বিশাল হয় (100005 এর চেয়ে 1e-5) এবং কোনও পিছনের শূন্যগুলি (1.00000 এর পরিবর্তে 1) এড়িয়ে যাওয়াটিকে অগ্রাহ্য করে exp
ccxvii

4
@ ট্রুথসিকার একটি আইইইই 754 বাইনারি 64 কোড উপস্থাপন করতে আসলে কমপক্ষে 15 টি উল্লেখযোগ্য দশমিক স্থান মুদ্রণ করা দরকার । তবে দ্বৈত সংখ্যায় (২,৪,৮, ইত্যাদিতে) যথার্থ পরিবর্তন হিসাবে দ্ব্যর্থহীন-নেসের 17 টি প্রয়োজন এবং দশমিক সংখ্যা (10,100,1000, ইত্যাদিতে) কখনও একই সংখ্যায় থাকে না (1.0 ব্যতীত)। উদাহরণ: 2 doubleমান শুধুমাত্র উপরের 0.1: 1.000_0000_0000_0000_2e-01, 1.000_0000_0000_0000_3e-01প্রয়োজন 17 ডিজিটের পার্থক্য।
chux - মনিকা পুনরায় ইনস্টল করুন 7'15

3
@ chux - আপনি% .16g এর আচরণ সম্পর্কে ভুল করেছেন; আপনার উদাহরণটি 1.000_0000_0000_0000_0000_2e-01 কে 1.000_0000_0000_0000_3e-01 এর থেকে আলাদা করার পক্ষে এটি পর্যাপ্ত নয় । % .17g প্রয়োজন।
ডন হ্যাচ

1
@Don ডিম পাড়া আমি সম্মত "%.16g"অপর্যাপ্ত এবং "%.17g"এবং "%.16e"যথেষ্ট। এর বিবরণগুলি %gআমার ভুল মনে পড়েছিল।
chux - মনিকা

23

আপনি যদি কেবলমাত্র বিটের প্রতি আগ্রহী হন (রেস হেক্স প্যাটার্ন) আপনি %aফর্ম্যাটটি ব্যবহার করতে পারেন । এটি আপনাকে গ্যারান্টি দেয়:

বেস 2-তে সঠিক উপস্থাপনা উপস্থিত থাকলে অন্যথায় দ্বিগুণ প্রকারের মানগুলিকে পৃথক করতে যথেষ্ট বড় হলে ডিফল্ট নির্ভুলতার মানটির যথাযথ প্রতিনিধিত্বের পক্ষে যথেষ্ট।

আমি যুক্ত করতে হবে যে এটি কেবল সি 99 এর জন্য উপলব্ধ।


16

না, সর্বাধিক নির্ভুলতার সাথে ভাসমান-পয়েন্ট মুদ্রণের জন্য এমন কোনও প্রিন্টফ প্রস্থ নির্দিষ্টকরণকারী নেই । কেন আমাকে ব্যাখ্যা করুন।

সর্বাধিক স্পষ্টতা floatএবং doubleহয় পরিবর্তনশীল , এবং উপর নির্ভরশীল প্রকৃত মূল্য এর floatবা double

প্রত্যাহার করুন floatএবং sign.exponal.mantissa ফর্ম্যাটে doubleসংরক্ষণ করা হয় । এর অর্থ হ'ল বড় সংখ্যার চেয়ে কম সংখ্যার জন্য ভগ্নাংশ উপাদানটির জন্য আরও অনেক বিট ব্যবহৃত হয়

এখানে চিত্র বর্ণনা লিখুন

উদাহরণস্বরূপ, floatসহজেই 0.0 এবং 0.1 এর মধ্যে পার্থক্য করতে পারে।

float r = 0;
printf( "%.6f\n", r ) ; // 0.000000
r+=0.1 ;
printf( "%.6f\n", r ) ; // 0.100000

তবে এবং floatএর মধ্যে পার্থক্য সম্পর্কে কোনও ধারণা নেই ।1e271e27 + 0.1

r = 1e27;
printf( "%.6f\n", r ) ; // 999999988484154753734934528.000000
r+=0.1 ;
printf( "%.6f\n", r ) ; // still 999999988484154753734934528.000000

এটি কারণ যে সমস্ত নির্ভুলতা (যা ম্যান্টিসা বিটের সংখ্যা দ্বারা সীমাবদ্ধ) দশমিকের বামে সংখ্যার বড় অংশের জন্য ব্যবহৃত হয়।

%.fপরিবর্তক ঠিক বলেছেন কত দশমিক মান আপনি যতটা ভাসা নম্বর থেকে মুদ্রণ করতে চান বিন্যাস যায়। সত্য যে সঠিকতা প্রাপ্তিসাধ্য সংখ্যা আকারের উপর নির্ভর করে আপ হয় প্রোগ্রামার হিসাবে আপনি হ্যান্ডেল করতে। printfআপনার পক্ষে এটি পরিচালনা করতে পারে না / করতে পারে না।


2
নির্দিষ্ট দশমিক স্থানে ভাসমান পয়েন্টের মানগুলি সঠিকভাবে মুদ্রণের সীমাবদ্ধতার একটি দুর্দান্ত ব্যাখ্যা। যাইহোক, আমি বিশ্বাস করি যে আমি আমার মূল শব্দগুলির পছন্দ সম্পর্কে খুব স্পষ্ট ছিলাম, সুতরাং আমি "সর্বাধিক নির্ভুলতা" শব্দটি এড়াতে আমার প্রশ্নটি আপডেট করেছি যে এটি বিভ্রান্তি দূর করতে পারে।
ভিলহেম গ্রে গ্রে

এটি এখনও আপনার মুদ্রণের সংখ্যাটির উপর নির্ভর করে।
বোবোবোবো

3
এটি আংশিক সত্য, তবে এটি প্রশ্নের উত্তর দেয় না এবং আপনি ওপি কী জিজ্ঞাসা করছে তা নিয়ে আপনি বিভ্রান্ত হয়ে পড়েছেন। তিনি জিজ্ঞাসা করছেন যে কেউ যদি উল্লেখযোগ্য [দশমিক] সংখ্যার কোনও floatসরবরাহের সংখ্যার প্রশ্ন করতে পারে এবং আপনি দৃ .়ভাবে বলেছেন যে এরকম কোনও জিনিস নেই (যেমন কোনও নেই FLT_DIG), যা ভুল।

@ H2CO3 হয়তো আপনার আমার পোস্ট এবং ডাউনওয়েট (জে / কে) সম্পাদনা করা উচিত। এই উত্তর জোর দিয়ে FLT_DIGকিছু বোঝায় না। এই উত্তরটি পাওয়া যায় দশমিক জায়গাগুলির সংখ্যা ভাসাটির অভ্যন্তরের মানের উপর নির্ভর করে
বোবোবোবো

1
আপনি কি ধরে নিচ্ছেন যে ফর্ম্যাট লেটারটি "চ" হতে হবে? আমি মনে করি না যে এটি প্রয়োজনীয়। আমার প্রশ্নটি পড়তে হ'ল ওপি এমন কিছু প্রিন্টফ ফর্ম্যাট সুনির্দিষ্ট সন্ধান করছে যা একটি অ-ক্ষতিগ্রস্থ রাউন্ড ট্রিপ তৈরি করে, সুতরাং @ সিসিএক্সভিয়ের উত্তর (ভাসমানের জন্য "% .9g", "% .17g" ডাবল জন্য) একটি ভাল একটা. সম্ভবত এটি থেকে "প্রস্থ" শব্দটি সরিয়ে প্রশ্নটি আরও ভাল করে বানানো হবে।
ডন হ্যাচ

11

কেবলমাত্র ম্যাক্রোগুলি থেকে <float.h>এবং ভেরিয়েবল-প্রস্থের রূপান্তর নির্দিষ্টকরণকারী ( ".*"):

float f = 3.14159265358979323846;
printf("%.*f\n", FLT_DIG, f);

2
@ অলিচর্লেসওয়ার্থ আপনার কি এমন অর্থ বোঝায়:printf("%." FLT_DIG "f\n", f);
ভিলহেলম গ্রে

3
+1 তবে এটি সবচেয়ে ভাল জন্য কাজ করে %e, %fএটির জন্য খুব ভাল নয় : কেবলমাত্র যদি জানা থাকে যে মুদ্রণের মানটি খুব কাছাকাছি 1.0
পাস্কেল কুয়াক

3
%eখুব অল্প সংখ্যক জন্য উল্লেখযোগ্য সংখ্যা মুদ্রণ %fকরে এবং না করে। যেমন x = 1e-100%.5fপ্রিন্ট 0.00000(মোটেও ছাড়ের ক্ষতি)। %.5eকপি করে প্রিন্ট 1.00000e-100
chux - মনিকা পুনরায় ইনস্টল করুন

1
@ বোবোবোও এছাড়াও, আপনি এটির থেকেও ভুল বলেছেন যে এটি "আরও সঠিক কারণ দেয়"। FLT_DIGএটি একটি কারণে এটি সংজ্ঞায়িত মানকে সংজ্ঞায়িত করা হয় যদি এটি 6 হয় তবে এর কারণ float6 টির বেশি নির্ভুলতা ধরে রাখতে সক্ষম নয়। আপনি যদি এটি ব্যবহার করে মুদ্রণ করেন %.7fতবে শেষ অঙ্কটির কোনও অর্থ হবে না। আপনি ডাউন ডাউন আগে চিন্তা করুন।

5
@ বোবোবো না, %.6fসমান নয়, কারণ FLT_DIGসর্বদা হয় না And এবং দক্ষতার বিষয়ে কে যত্ন করে? I / O ইতিমধ্যে নরকের হিসাবে ব্যয়বহুল, এক অঙ্কের কম-বেশি নির্ভুলতা কোনও বাধা তৈরি করবে না।

5

মুদ্রণটি DBL_DECIMAL_DIGসত্যই সংখ্যার বাইনারি উপস্থাপনা সংরক্ষণ করে তা যাচাই করতে আমি একটি ছোট পরীক্ষা চালিয়েছি। দেখা গেল যে কম্পাইলার এবং সি লাইব্রেরিগুলির জন্য আমি চেষ্টা করেছি, DBL_DECIMAL_DIGতা হ'ল প্রয়োজনীয় সংখ্যার সংখ্যা এবং এমনকি আরও একটি অঙ্কের সাথে মুদ্রণ একটি উল্লেখযোগ্য সমস্যা তৈরি করে।

#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

union {
    short s[4];
    double d;
} u;

void
test(int digits)
{
    int i, j;
    char buff[40];
    double d2;
    int n, num_equal, bin_equal;

    srand(17);
    n = num_equal = bin_equal = 0;
    for (i = 0; i < 1000000; i++) {
        for (j = 0; j < 4; j++)
            u.s[j] = (rand() << 8) ^ rand();
        if (isnan(u.d))
            continue;
        n++;
        sprintf(buff, "%.*g", digits, u.d);
        sscanf(buff, "%lg", &d2);
        if (u.d == d2)
            num_equal++;
        if (memcmp(&u.d, &d2, sizeof(double)) == 0)
            bin_equal++;
    }
    printf("Tested %d values with %d digits: %d found numericaly equal, %d found binary equal\n", n, digits, num_equal, bin_equal);
}

int
main()
{
    test(DBL_DECIMAL_DIG);
    test(DBL_DECIMAL_DIG - 1);
    return 0;
}

আমি মাইক্রোসফ্টের সি সংকলক 19.00.24215.1 এবং জিসিসি সংস্করণ 7.4.0 20170516 (দেবিয়ান 6.3.0-18 + দেবেন 9 ইউ 1) দিয়ে এটি চালাচ্ছি। একটি কম দশমিক অঙ্ক ব্যবহার করা সংখ্যার অর্ধেককে ঠিক সমান তুলনা করে। (আমি এটিও যাচাই করেছি যে rand()ব্যবহৃত হিসাবে প্রকৃতপক্ষে প্রায় এক মিলিয়ন বিভিন্ন সংখ্যা উত্পাদন করে)) এখানে বিস্তারিত ফলাফল রয়েছে।

মাইক্রোসফ্ট সি

17 অঙ্ক সহ 999507 মান পরীক্ষা করা হয়েছে: 999507 সংখ্যার সমান, 999507 বাইনারি সমান পাওয়া গেছে
16 অঙ্ক সহ 999507 মান পরীক্ষা করা হয়েছে: 545389 সংখ্যাটি সমান পাওয়া গেছে, 545389 বাইনারি সমান পাওয়া গেছে

জিসিসি

17 সংখ্যা সহ 999485 মান পরীক্ষা করা হয়েছে: 999485 সংখ্যার সমান, 999485 পাওয়া বাইনারি সমান
16 অঙ্ক সহ 999485 মান পরীক্ষা করা হয়েছে: 545402 সংখ্যার সমান, 545402 পাওয়া বাইনারি সমান

1
"এটি মাইক্রোসফ্টের সি সংকলক দিয়ে চালান" -> সেই সংকলকটি থাকতে পারে RAND_MAX == 32767। বিবেচনা করুন u.s[j] = (rand() << 8) ^ rand();বা নির্দিষ্ট কিছু বিটগুলি 0 বা 1 হওয়ার সুযোগ পাবেন
chux - মনিকা পুনরায় স্থাপন করুন

প্রকৃতপক্ষে, এর RAND_MAX 32767, সুতরাং আপনার প্রস্তাবটি সঠিক।
ডায়োমিডিস স্পিনেলিস

1
@ Chux-ReinstateMonica এর পরামর্শ অনুসারে আমি RAND_MAX কে পরিচালনা করার জন্য পোস্টটি আপডেট করেছি। ফলাফলগুলি আগে প্রাপ্তগুলির অনুরূপ।
ডায়োমিডিস স্পিনেলিস

3

উত্তরে আমার একটি মন্তব্যে আমি বিলাপ করে বলেছিলাম যে দশকের আকারে ভাসমান বিন্দুতে সমস্ত উল্লেখযোগ্য অঙ্কগুলি মুদ্রণের জন্য আমি দীর্ঘ সময় চেয়েছিলাম, যেমনটি প্রশ্ন জিজ্ঞাসা করে ঠিক তেমনভাবে। আচ্ছা আমি অবশেষে বসে এটি লিখেছিলাম। এটি পুরোপুরি নিখুঁত নয় এবং এটি ডেমো কোড যা অতিরিক্ত তথ্য মুদ্রণ করে তবে এটি বেশিরভাগ ক্ষেত্রে আমার পরীক্ষার জন্য কাজ করে। আপনি (যেমন যে কেউ) পুরো মোড়ক প্রোগ্রামটির একটি অনুলিপি চান যা এটি পরীক্ষার জন্য চালিত করে তা দয়া করে আমাকে জানান।

static unsigned int
ilog10(uintmax_t v);

/*
 * Note:  As presented this demo code prints a whole line including information
 * about how the form was arrived with, as well as in certain cases a couple of
 * interesting details about the number, such as the number of decimal places,
 * and possibley the magnitude of the value and the number of significant
 * digits.
 */
void
print_decimal(double d)
{
        size_t sigdig;
        int dplaces;
        double flintmax;

        /*
         * If we really want to see a plain decimal presentation with all of
         * the possible significant digits of precision for a floating point
         * number, then we must calculate the correct number of decimal places
         * to show with "%.*f" as follows.
         *
         * This is in lieu of always using either full on scientific notation
         * with "%e" (where the presentation is always in decimal format so we
         * can directly print the maximum number of significant digits
         * supported by the representation, taking into acount the one digit
         * represented by by the leading digit)
         *
         *        printf("%1.*e", DBL_DECIMAL_DIG - 1, d)
         *
         * or using the built-in human-friendly formatting with "%g" (where a
         * '*' parameter is used as the number of significant digits to print
         * and so we can just print exactly the maximum number supported by the
         * representation)
         *
         *         printf("%.*g", DBL_DECIMAL_DIG, d)
         *
         *
         * N.B.:  If we want the printed result to again survive a round-trip
         * conversion to binary and back, and to be rounded to a human-friendly
         * number, then we can only print DBL_DIG significant digits (instead
         * of the larger DBL_DECIMAL_DIG digits).
         *
         * Note:  "flintmax" here refers to the largest consecutive integer
         * that can be safely stored in a floating point variable without
         * losing precision.
         */
#ifdef PRINT_ROUND_TRIP_SAFE
# ifdef DBL_DIG
        sigdig = DBL_DIG;
# else
        sigdig = ilog10(uipow(FLT_RADIX, DBL_MANT_DIG - 1));
# endif
#else
# ifdef DBL_DECIMAL_DIG
        sigdig = DBL_DECIMAL_DIG;
# else
        sigdig = (size_t) lrint(ceil(DBL_MANT_DIG * log10((double) FLT_RADIX))) + 1;
# endif
#endif
        flintmax = pow((double) FLT_RADIX, (double) DBL_MANT_DIG); /* xxx use uipow() */
        if (d == 0.0) {
                printf("z = %.*s\n", (int) sigdig + 1, "0.000000000000000000000"); /* 21 */
        } else if (fabs(d) >= 0.1 &&
                   fabs(d) <= flintmax) {
                dplaces = (int) (sigdig - (size_t) lrint(ceil(log10(ceil(fabs(d))))));
                if (dplaces < 0) {
                        /* XXX this is likely never less than -1 */
                        /*
                         * XXX the last digit is not significant!!! XXX
                         *
                         * This should also be printed with sprintf() and edited...
                         */
                        printf("R = %.0f [%d too many significant digits!!!, zero decimal places]\n", d, abs(dplaces));
                } else if (dplaces == 0) {
                        /*
                         * The decimal fraction here is not significant and
                         * should always be zero  (XXX I've never seen this)
                         */
                        printf("R = %.0f [zero decimal places]\n", d);
                } else {
                        if (fabs(d) == 1.0) {
                                /*
                                 * This is a special case where the calculation
                                 * is off by one because log10(1.0) is 0, but
                                 * we still have the leading '1' whole digit to
                                 * count as a significant digit.
                                 */
#if 0
                                printf("ceil(1.0) = %f, log10(ceil(1.0)) = %f, ceil(log10(ceil(1.0))) = %f\n",
                                       ceil(fabs(d)), log10(ceil(fabs(d))), ceil(log10(ceil(fabs(d)))));
#endif
                                dplaces--;
                        }
                        /* this is really the "useful" range of %f */
                        printf("r = %.*f [%d decimal places]\n", dplaces, d, dplaces);
                }
        } else {
                if (fabs(d) < 1.0) {
                        int lz;

                        lz = abs((int) lrint(floor(log10(fabs(d)))));
                        /* i.e. add # of leading zeros to the precision */
                        dplaces = (int) sigdig - 1 + lz;
                        printf("f = %.*f [%d decimal places]\n", dplaces, d, dplaces);
                } else {                /* d > flintmax */
                        size_t n;
                        size_t i;
                        char *df;

                        /*
                         * hmmmm...  the easy way to suppress the "invalid",
                         * i.e. non-significant digits is to do a string
                         * replacement of all dgits after the first
                         * DBL_DECIMAL_DIG to convert them to zeros, and to
                         * round the least significant digit.
                         */
                        df = malloc((size_t) 1);
                        n = (size_t) snprintf(df, (size_t) 1, "%.1f", d);
                        n++;                /* for the NUL */
                        df = realloc(df, n);
                        (void) snprintf(df, n, "%.1f", d);
                        if ((n - 2) > sigdig) {
                                /*
                                 * XXX rounding the integer part here is "hard"
                                 * -- we would have to convert the digits up to
                                 * this point back into a binary format and
                                 * round that value appropriately in order to
                                 * do it correctly.
                                 */
                                if (df[sigdig] >= '5' && df[sigdig] <= '9') {
                                        if (df[sigdig - 1] == '9') {
                                                /*
                                                 * xxx fixing this is left as
                                                 * an exercise to the reader!
                                                 */
                                                printf("F = *** failed to round integer part at the least significant digit!!! ***\n");
                                                free(df);
                                                return;
                                        } else {
                                                df[sigdig - 1]++;
                                        }
                                }
                                for (i = sigdig; df[i] != '.'; i++) {
                                        df[i] = '0';
                                }
                        } else {
                                i = n - 1; /* less the NUL */
                                if (isnan(d) || isinf(d)) {
                                        sigdig = 0; /* "nan" or "inf" */
                                }
                        }
                        printf("F = %.*s. [0 decimal places, %lu digits, %lu digits significant]\n",
                               (int) i, df, (unsigned long int) i, (unsigned long int) sigdig);
                        free(df);
                }
        }

        return;
}


static unsigned int
msb(uintmax_t v)
{
        unsigned int mb = 0;

        while (v >>= 1) { /* unroll for more speed...  (see ilog2()) */
                mb++;
        }

        return mb;
}

static unsigned int
ilog10(uintmax_t v)
{
        unsigned int r;
        static unsigned long long int const PowersOf10[] =
                { 1LLU, 10LLU, 100LLU, 1000LLU, 10000LLU, 100000LLU, 1000000LLU,
                  10000000LLU, 100000000LLU, 1000000000LLU, 10000000000LLU,
                  100000000000LLU, 1000000000000LLU, 10000000000000LLU,
                  100000000000000LLU, 1000000000000000LLU, 10000000000000000LLU,
                  100000000000000000LLU, 1000000000000000000LLU,
                  10000000000000000000LLU };

        if (!v) {
                return ~0U;
        }
        /*
         * By the relationship "log10(v) = log2(v) / log2(10)", we need to
         * multiply "log2(v)" by "1 / log2(10)", which is approximately
         * 1233/4096, or (1233, followed by a right shift of 12).
         *
         * Finally, since the result is only an approximation that may be off
         * by one, the exact value is found by subtracting "v < PowersOf10[r]"
         * from the result.
         */
        r = ((msb(v) * 1233) >> 12) + 1;

        return r - (v < PowersOf10[r]);
}

এটি প্রশ্নের উত্তর দেয় কি না সে বিষয়ে আমার খেয়াল নেই - এটি করা সত্যিই চিত্তাকর্ষক। এটি কিছুটা চিন্তাভাবনা নিয়েছিল এবং স্বীকৃতি ও প্রশংসা করা উচিত। আপনি যদি কোনওভাবে (এখানে বা অন্য যাই হোক না কেন) পরীক্ষার জন্য পুরো কোডটি অন্তর্ভুক্ত করেন তবে এটি ভাল না হলেও এটি সত্যিই খুব ভাল কাজ। তার জন্য একটি +1 করুন!
প্রাইফটান

0

আমার জ্ঞানের মতে , এখানে একটি ভাল সংশ্লেষিত অ্যালগরিদম রয়েছে যাতে প্রয়োজনীয় সংখ্যার উল্লেখযোগ্য সংখ্যায় আউটপুট দেয় যেমন স্ট্রিংটি আবার স্ক্যান করার সময়, মূল ভাসমান পয়েন্টের মানdtoa.c ড্যানিয়েল গে দ্বারা লিখিতভাবে অর্জন করা হয় , যা এখানে নেটলিবে পাওয়া যায় (দেখুন) এছাড়াও সম্পর্কিত কাগজ )। এই কোডটি ব্যবহার করা হয় যেমন পাইথন, মাইএসকিউএল, সায়্লাব এবং আরও অনেকগুলিতে।

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