मैं C में दो दशमलव स्थानों (37.78) पर फ्लोट वैल्यू (जैसे 37.777779) कैसे राउंड कर सकता हूं?
मैं C में दो दशमलव स्थानों (37.78) पर फ्लोट वैल्यू (जैसे 37.777779) कैसे राउंड कर सकता हूं?
जवाबों:
यदि आप केवल आउटपुट उद्देश्यों के लिए संख्या को गोल करना चाहते हैं, तो "%.2f"
प्रारूप स्ट्रिंग वास्तव में सही उत्तर है। हालाँकि, यदि आप वास्तव में आगे की गणना के लिए फ्लोटिंग पॉइंट वैल्यू को गोल करना चाहते हैं, तो निम्न कार्य जैसे कुछ:
#include <math.h>
float val = 37.777779;
float rounded_down = floorf(val * 100) / 100; /* Result: 37.77 */
float nearest = roundf(val * 100) / 100; /* Result: 37.78 */
float rounded_up = ceilf(val * 100) / 100; /* Result: 37.78 */
ध्यान दें कि तीन अलग-अलग राउंडिंग नियम हैं जिन्हें आप चुनना चाहते हैं: राउंड डाउन (यानी, दो दशमलव स्थानों के बाद कम करें), गोल से निकटतम, और राउंड अप। आमतौर पर, आप निकटतम दौर चाहते हैं।
जैसा कि कई अन्य लोगों ने बताया है कि फ्लोटिंग पॉइंट प्रतिनिधित्व के प्रश्नों के कारण, ये गोल मान बिल्कुल "स्पष्ट" दशमलव मान नहीं हो सकते हैं, लेकिन वे बहुत करीब होंगे।
राउंडिंग के बारे में अधिक (बहुत!) अधिक जानकारी के लिए, और विशेष रूप से निकटतम के लिए राउंड -ब्रेकिंग नियमों पर, राउंडिंग पर विकिपीडिया लेख देखें ।
doubles
किसी तरह कर सकता हूं ? लगता है कि मैं जो काम करना चाहता हूँ वह नहीं करता :( (का उपयोग करके floor
और ceil
)
मान लें कि आप मुद्रण के लिए मूल्य दौर के बारे में बात कर रहे हैं, तो एंड्रयू Coleson और अरक के जवाब सही हैं:
printf("%.2f", 37.777779);
लेकिन ध्यान दें कि यदि आप आंतरिक उपयोग के लिए संख्या को 37.78 पर गोल करने का लक्ष्य बना रहे हैं (उदाहरण के लिए किसी अन्य मूल्य के खिलाफ तुलना करने के लिए), तो यह एक अच्छा विचार नहीं है, जिस तरह से फ्लोटिंग पॉइंट नंबर काम करते हैं: आप आमतौर पर नहीं करते हैं फ्लोटिंग पॉइंट के लिए समानता तुलना करना चाहते हैं, इसके बजाय एक लक्ष्य मान +/- एक सिग्मा मान का उपयोग करें। या संख्या को एक ज्ञात परिशुद्धता के साथ एक स्ट्रिंग के रूप में एन्कोड करें, और तुलना करें।
संबंधित प्रश्न के लिए ग्रेग हेगिल के उत्तर के लिंक को देखें , जिसमें यह भी शामिल है कि आपको वित्तीय गणना के लिए फ़्लोटिंग पॉइंट का उपयोग क्यों नहीं करना चाहिए।
printf("%.*f", (int)precision, (double)number);
इस बारे में कैसा है:
float value = 37.777779;
float rounded = ((int)(value * 100 + .5) / 100.0);
printf("%.2f", 37.777779);
यदि आप सी-स्ट्रिंग लिखना चाहते हैं:
char number[24]; // dummy size, you should take care of the size!
sprintf(number, "%.2f", 37.777779);
वहाँ दौर एक के लिए एक रास्ता नहीं है float
दूसरे के लिए float
क्योंकि गोल float
प्रदर्शनीय नहीं हो सकता है (फ्लोटिंग प्वाइंट नंबर की एक सीमा)। उदाहरण के लिए, आप 37.777779 से 37.78 के बीच में हैं, लेकिन सबसे अधिक प्रतिनिधित्व करने वाली संख्या 37.781 है।
हालाँकि, आप एक प्रारूप स्ट्रिंग फ़ंक्शन का उपयोग करके "राउंड" कर सकते हैंfloat
।
float
n से n दशमलव स्थानों पर चक्कर नहीं लगा सकते हैं और फिर परिणाम की अपेक्षा हमेशा n दशमलव स्थानों की होगी। आप अभी भी एक मिलेगा float
, बस एक आप की उम्मीद नहीं है।
इसके अलावा, यदि आप C ++ का उपयोग कर रहे हैं, तो आप इस तरह से एक फंक्शन बना सकते हैं:
string prd(const double x, const int decDigits) {
stringstream ss;
ss << fixed;
ss.precision(decDigits); // set # places after decimal
ss << x;
return ss.str();
}
आप इस तरह कोड के साथ दशमलव बिंदु के बाद स्थानों के myDouble
साथ किसी भी डबल उत्पादन कर सकते n
हैं:
std::cout << prd(myDouble,n);
आप अभी भी उपयोग कर सकते हैं:
float ceilf(float x); // don't forget #include <math.h> and link with -lm.
उदाहरण:
float valueToRound = 37.777779;
float roundedValue = ceilf(valueToRound * 100) / 100;
C ++ में (या C- शैली के कलाकारों के साथ C) में, आप फ़ंक्शन बना सकते हैं:
/* Function to control # of decimal places to be output for x */
double showDecimals(const double& x, const int& numDecimals) {
int y=x;
double z=x-y;
double m=pow(10,numDecimals);
double q=z*m;
double r=round(q);
return static_cast<double>(y)+(1.0/m)*r;
}
फिर std::cout << showDecimals(37.777779,2);
उत्पादन होगा: 37.78।
जाहिर है आपको वास्तव में उस फ़ंक्शन में सभी 5 चर बनाने की आवश्यकता नहीं है, लेकिन मैं उन्हें वहां छोड़ देता हूं ताकि आप तर्क देख सकें। संभवतः सरल समाधान हैं, लेकिन यह मेरे लिए अच्छी तरह से काम करता है - खासकर क्योंकि यह मुझे उस दशमलव स्थान के बाद अंकों की संख्या को समायोजित करने की अनुमति देता है जो मुझे चाहिए।
इसके लिए हमेशा printf
परिवार के कार्यों का उपयोग करें। यहां तक कि अगर आप मान को एक फ्लोट के रूप में प्राप्त करना चाहते हैं, तो आप snprintf
एक स्ट्रिंग के रूप में गोल मूल्य प्राप्त करने और फिर इसे वापस पार्स करने के लिए उपयोग कर रहे हैं atof
:
#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
double dround(double val, int dp) {
int charsNeeded = 1 + snprintf(NULL, 0, "%.*f", dp, val);
char *buffer = malloc(charsNeeded);
snprintf(buffer, charsNeeded, "%.*f", dp, val);
double result = atof(buffer);
free(buffer);
return result;
}
मैं ऐसा इसलिए कहता हूं क्योंकि वर्तमान में शीर्ष-वोट किए गए उत्तर और यहां कई अन्य लोगों द्वारा दिखाए गए दृष्टिकोण - 100 से गुणा करना, निकटतम पूर्णांक तक घूमना, और फिर 100 से फिर से विभाजित करना - दो तरीकों से त्रुटिपूर्ण है:
पहली तरह की त्रुटि को स्पष्ट करने के लिए - गोलाई दिशा कभी-कभी गलत होने पर - इस कार्यक्रम को चलाने का प्रयास करें:
int main(void) {
// This number is EXACTLY representable as a double
double x = 0.01499999999999999944488848768742172978818416595458984375;
printf("x: %.50f\n", x);
double res1 = dround(x, 2);
double res2 = round(100 * x) / 100;
printf("Rounded with snprintf: %.50f\n", res1);
printf("Rounded with round, then divided: %.50f\n", res2);
}
आप इस आउटपुट को देखेंगे:
x: 0.01499999999999999944488848768742172978818416595459
Rounded with snprintf: 0.01000000000000000020816681711721685132943093776703
Rounded with round, then divided: 0.02000000000000000041633363423443370265886187553406
ध्यान दें कि हमने जो मूल्य शुरू किया था वह 0.015 से कम था, और इसलिए इसे 2 दशमलव स्थानों पर गोल करते समय गणितीय रूप से सही उत्तर 0.01 है। बेशक, 0.01 एक डबल के रूप में बिल्कुल प्रतिनिधित्व योग्य नहीं है , लेकिन हम उम्मीद करते हैं कि हमारा परिणाम 0.01 के करीब डबल हो। उपयोग करने snprintf
से हमें वह परिणाम मिलता है, लेकिन उपयोग करने round(100 * x) / 100
से हमें 0.02 मिलते हैं, जो गलत है। क्यों? क्योंकि 100 * x
परिणाम के रूप में हमें ठीक 1.5 देता है। इस प्रकार 100 से गुणा करने से सही दिशा बदल जाती है।
दूसरी तरह की त्रुटि का वर्णन करने के लिए - परिणाम कभी-कभी गलत होने के कारण * 100
और / 100
सही मायने में एक-दूसरे के विपरीत नहीं होने के कारण - हम एक बहुत बड़ी संख्या के साथ एक समान व्यायाम कर सकते हैं:
int main(void) {
double x = 8631192423766613.0;
printf("x: %.1f\n", x);
double res1 = dround(x, 2);
double res2 = round(100 * x) / 100;
printf("Rounded with snprintf: %.1f\n", res1);
printf("Rounded with round, then divided: %.1f\n", res2);
}
हमारी संख्या में अब भिन्नात्मक भाग भी नहीं है; यह पूर्णांक मान है, बस प्रकार के साथ संग्रहीत किया जाता है double
। तो इसे राउंड करने के बाद परिणाम वही होना चाहिए जो हमने शुरू किया था, है ना?
यदि आप ऊपर कार्यक्रम चलाते हैं, तो आप देखेंगे:
x: 8631192423766613.0
Rounded with snprintf: 8631192423766613.0
Rounded with round, then divided: 8631192423766612.0
उफ़। हमारा snprintf
तरीका फिर से सही परिणाम देता है, लेकिन गुणा-फिर-दौर-तब-विभाजन दृष्टिकोण विफल हो जाता है। ऐसा इसलिए है क्योंकि गणितीय रूप से सही मान 8631192423766613.0 * 100
, 863119242376661300.0
एक डबल के रूप में बिल्कुल प्रतिनिधित्व योग्य नहीं है; निकटतम मूल्य है 863119242376661248.0
। जब आप उस पीठ को 100 से विभाजित करते हैं, तो आप प्राप्त करते हैं 8631192423766612.0
- आपके द्वारा शुरू की गई एक अलग संख्या।
उम्मीद है कि एक पर्याप्त प्रदर्शन है कि roundf
कई दशमलव स्थानों के लिए उपयोग करने के लिए टूट गया है, और आप snprintf
इसके बजाय का उपयोग करना चाहिए । यदि वह आपको एक भयानक हैक की तरह लगता है, तो शायद आप इस ज्ञान से आश्वस्त होंगे कि यह मूल रूप से सीपीथॉन क्या करता है ।
का उपयोग करें float roundf(float x)
।
"राउंड फ़ंक्शंस फ़्लोज़िंग-पॉइंट प्रारूप में निकटतम पूर्णांक मान के लिए अपने तर्क को गोल करते हैं, वर्तमान दौर की दिशा की परवाह किए बिना, आधे मामलों को शून्य से दूर करते हुए।" C11dr 117.12.9.5
#include <math.h>
float y = roundf(x * 100.0f) / 100.0f;
आपके float
कार्यान्वयन के आधार पर , वे संख्याएँ जो आधी-अधूरी प्रतीत हो सकती हैं, नहीं हैं। फ्लोटिंग-पॉइंट आम तौर पर बेस -2 ओरिएंटेड होता है। इसके अलावा, 0.01
सभी "अर्ध-मार्ग" मामलों पर निकटतम को गोल करना सबसे चुनौतीपूर्ण है।
void r100(const char *s) {
float x, y;
sscanf(s, "%f", &x);
y = round(x*100.0)/100.0;
printf("%6s %.12e %.12e\n", s, x, y);
}
int main(void) {
r100("1.115");
r100("1.125");
r100("1.135");
return 0;
}
1.115 1.115000009537e+00 1.120000004768e+00
1.125 1.125000000000e+00 1.129999995232e+00
1.135 1.134999990463e+00 1.139999985695e+00
हालाँकि, 1.11 और 1.12 के बीच "1.115" "अर्ध-मार्ग" है, जब इसे रूपांतरित किया जाता है float
, तो मान नहीं है 1.115000009537...
और यह "अर्ध-मार्ग" नहीं है, लेकिन 1.12 के करीब है और निकटतम float
है1.120000004768...
1. १.१२० "१.१२ और १.१३ के बीच" अर्ध-मार्ग "है, जब इसे रूपांतरित किया जाता है float
, तो मान बिल्कुल 1.125
" आधा-रास्ता "है। यहां तक कि नियम से जुड़ा होने के कारण यह 1.13 की ओर घूमता है और सबसे निकटतम गोल होता float
है1.129999995232...
यद्यपि "1.135" 1.13 और 1.14 के बीच "अर्ध-मार्ग" है, जब इसे रूपांतरित किया जाता है float
, तो मान नहीं है 1.134999990463...
और यह "अर्ध-मार्ग" नहीं है, लेकिन 1.13 के करीब है और निकटतम float
है1.129999995232...
यदि कोड का उपयोग किया
y = roundf(x*100.0f)/100.0f;
हालांकि "1.135" "आधे रास्ते" 1.13 और 1.14 के बीच, जब में बदल जाती है float
, मूल्य है 1.134999990463...
और अब "आधे रास्ते" है, लेकिन करीब के लिए 1.13 लेकिन गलत तरीके से करने के लिए राउंड float
के 1.139999985695...
के और अधिक सीमित परिशुद्धता के कारण float
बनाम double
। कोडिंग लक्ष्यों के आधार पर इस गलत मान को सही माना जा सकता है।
मैंने फ्लोट संख्याओं को गोल करने के लिए यह मैक्रो बनाया। इसे अपने हेडर / फाइल में से एक में जोड़ें
#define ROUNDF(f, c) (((float)((int)((f) * (c))) / (c)))
यहाँ एक उदाहरण है:
float x = ROUNDF(3.141592, 100)
x बराबर 3.14 :)
double f_round(double dval, int n)
{
char l_fmtp[32], l_buf[64];
char *p_str;
sprintf (l_fmtp, "%%.%df", n);
if (dval>=0)
sprintf (l_buf, l_fmtp, dval);
else
sprintf (l_buf, l_fmtp, dval);
return ((double)strtod(l_buf, &p_str));
}
यहाँ n
दशमलव की संख्या है
उदाहरण:
double d = 100.23456;
printf("%f", f_round(d, 4));// result: 100.2346
printf("%f", f_round(d, 2));// result: 100.23
dval
3 विशाल है) अजीब if
/ else
ब्लॉक जहां आप प्रत्येक शाखा में बिल्कुल एक ही काम करते हैं। , और 4) sprintf
एक दूसरी sprintf
कॉल के लिए प्रारूप विनिर्देशक बनाने के लिए अति-उपयोग ; केवल कॉल के .*
लिए तर्क के रूप में दशमलव स्थानों के दोहरे मान और संख्या का उपयोग करना और पास करना सरल है sprintf
।
#define roundz(x,d) ((floor(((x)*pow(10,d))+.5))/pow(10,d))
a = 8.000000
sqrt(a) = r = 2.828427
roundz(r,2) = 2.830000
roundz(r,3) = 2.828000
roundz(r,5) = 2.828430
मुझे पहले इस सवाल का एक और जवाब जोड़ने के लिए मेरे कारण को सही ठहराने का प्रयास करने दें। एक आदर्श दुनिया में, गोलाई वास्तव में कोई बड़ी बात नहीं है। हालाँकि, वास्तविक प्रणालियों में, आपको कई मुद्दों से जूझने की आवश्यकता हो सकती है, जिसका परिणाम यह हो सकता है कि आप जो अपेक्षा करते हैं वह नहीं हो सकता। उदाहरण के लिए, आप वित्तीय गणना कर रहे होंगे, जहां अंतिम परिणाम राउंड किए जाते हैं और उपयोगकर्ताओं को 2 दशमलव स्थानों के रूप में प्रदर्शित किए जाते हैं; इन समान मूल्यों को एक डेटाबेस में निश्चित परिशुद्धता के साथ संग्रहीत किया जाता है, जिसमें 2 से अधिक दशमलव स्थान शामिल हो सकते हैं (विभिन्न कारणों से; रखने के लिए कोई इष्टतम स्थान नहीं है ... विशिष्ट स्थितियों पर निर्भर करता है प्रत्येक प्रणाली का समर्थन करना चाहिए, जैसे छोटे आइटम जिनकी कीमतें हैं प्रति यूनिट एक पैसा के अंश हैं); और, फ़्लोटिंग पॉइंट कंप्यूटेशन उन मानों पर किए जाते हैं जहाँ परिणाम प्लस / माइनस एप्सिलॉन होते हैं। मैं इन मुद्दों का सामना कर रहा हूं और वर्षों से अपनी रणनीति तैयार कर रहा हूं। मैं यह दावा नहीं करूंगा कि मैंने हर परिदृश्य का सामना किया है या सबसे अच्छा जवाब दिया है, लेकिन नीचे मेरे दृष्टिकोण का एक उदाहरण है जो अब तक इन मुद्दों पर काबू पा लेता है:
मान लीजिए कि 6 दशमलव स्थानों को फ़्लोट्स / डबल्स (विशिष्ट एप्लिकेशन के लिए एक मनमाना निर्णय) पर गणना के लिए पर्याप्त सटीकता के रूप में माना जाता है, निम्न राउंडिंग फ़ंक्शन / विधि का उपयोग करते हुए:
double Round(double x, int p)
{
if (x != 0.0) {
return ((floor((fabs(x)*pow(double(10.0),p))+0.5))/pow(double(10.0),p))*(x/fabs(x));
} else {
return 0.0;
}
}
किसी परिणाम की प्रस्तुति के लिए 2 दशमलव स्थानों पर गोलाई इस प्रकार की जा सकती है:
double val;
// ...perform calculations on val
String(Round(Round(Round(val,8),6),2));
के लिए val = 6.825
, परिणाम 6.83
उम्मीद के मुताबिक है।
के लिए val = 6.824999
, परिणाम है 6.82
। यहाँ धारणा यह है कि गणना ठीक इसके परिणामस्वरूप हुई 6.824999
और 7 वें दशमलव स्थान शून्य है।
के लिए val = 6.8249999
, परिणाम है 6.83
। 9
इस मामले में 7 वाँ दशमलव स्थान Round(val,6)
अपेक्षित परिणाम देने के लिए फ़ंक्शन का कारण बनता है । इस मामले के लिए, अनुगामी 9
s की कोई संख्या हो सकती है ।
के लिए val = 6.824999499999
, परिणाम है 6.83
। पहले कदम के रूप में 8 वें दशमलव स्थान पर गोलाई, यानी Round(val,8)
, एक बुरा मामले की देखभाल करता है जिसके द्वारा एक गणना फ़्लोटिंग पॉइंट परिणाम की गणना करता है 6.8249995
, लेकिन आंतरिक रूप से इसका प्रतिनिधित्व किया जाता है 6.824999499999...
।
अंत में, प्रश्न से उदाहरण ... में val = 37.777779
परिणाम 37.78
।
इस दृष्टिकोण को और अधिक सामान्यीकृत किया जा सकता है:
double val;
// ...perform calculations on val
String(Round(Round(Round(val,N+2),N),2));
जहां N फ़्लोट्स / डबल्स पर सभी मध्यवर्ती गणनाओं के लिए बनाए रखने के लिए सटीक है। यह नकारात्मक मूल्यों पर भी काम करता है। मुझे नहीं पता कि यह दृष्टिकोण गणितीय रूप से सभी संभावनाओं के लिए सही है या नहीं।
एक नंबर को गोल करने के लिए सरल सी कोड:
float n = 3.56;
printf("%.f", n);
यह आउटपुट होगा:
4
... या आप इसे बिना किसी पुस्तकालयों के पुराने ढंग से कर सकते हैं:
float a = 37.777779;
int b = a; // b = 37
float c = a - b; // c = 0.777779
c *= 100; // c = 77.777863
int d = c; // d = 77;
a = b + d / (float)100; // a = 37.770000;
यदि आप संख्या से अतिरिक्त जानकारी निकालना चाहते हैं तो बेशक।
यह फ़ंक्शन संख्या और सटीकता लेता है और गोल बंद संख्या को लौटाता है
float roundoff(float num,int precision)
{
int temp=(int )(num*pow(10,precision));
int num1=num*pow(10,precision+1);
temp*=10;
temp+=5;
if(num1>=temp)
num1+=10;
num1/=10;
num1*=10;
num=num1/pow(10,precision+1);
return num;
}
यह फ्लोटिंग पॉइंट नंबर को इंट में छोड़ देता है, पॉइंट को लेफ्ट शिफ्ट करके और पांच से ज्यादा कंडीशन के लिए चेक करता है।
float
(औरdouble
) दशमलव फ़्लोटिंग-पॉइंट नहीं हैं - वे बाइनरी फ़्लोटिंग-पॉइंट हैं - इसलिए दशमलव स्थिति के लिए राउंडिंग अर्थहीन है। हालाँकि, आप आउटपुट को राउंड कर सकते हैं।