महत्वपूर्ण अंकों की एक मनमानी संख्या के लिए गोलाई


83

आप किसी भी संख्या (न केवल पूर्णांकों> 0) को एन महत्वपूर्ण अंकों में कैसे गोल कर सकते हैं ?

उदाहरण के लिए, यदि मैं तीन महत्वपूर्ण अंकों के लिए चक्कर लगाना चाहता हूं, तो मुझे एक ऐसे फार्मूले की तलाश है जो ले सके:

1,239,451 और वापसी 1,240,000

12.1257 और वापसी 12.1

.0681 और वापसी .0681

५ और वापसी ५

स्वाभाविक रूप से एल्गोरिथ्म केवल 3 के एन को संभालने के लिए हार्ड-कोडेड नहीं होना चाहिए, हालांकि यह एक शुरुआत होगी।


प्रश्न बहुत सामान्य लगता है। विभिन्न प्रोग्रामिंग भाषाओं में ऐसा करने के लिए अलग-अलग मानक कार्य होते हैं। वास्तव में पहिया को सुदृढ़ करने के लिए उपयुक्त नहीं है।
जॉनी वोंग

जवाबों:


106

यहाँ 12.100000000000001 बग अन्य उत्तर के बिना जावा में एक ही कोड है

मैंने दोहराए गए कोड को भी हटा दिया, powerजब चल रहे मुद्दों को रोकने के लिए एक प्रकार के पूर्णांक में बदल दिया n - d, और लंबे मध्यवर्ती को अधिक स्पष्ट कर दिया

बग एक छोटी संख्या के साथ बड़ी संख्या को गुणा करने के कारण हुआ था। इसके बजाय मैं समान आकार की दो संख्याओं को विभाजित करता हूं।

संपादित करें
और अधिक बग फिक्स्ड। जोड़ा 0 के लिए जाँच के रूप में यह NaN में परिणाम होगा। फ़ंक्शन वास्तव में नकारात्मक संख्याओं के साथ काम करता है (मूल कोड नकारात्मक संख्याओं को संभालता नहीं है क्योंकि नकारात्मक संख्या का लॉग एक जटिल संख्या है)

public static double roundToSignificantFigures(double num, int n) {
    if(num == 0) {
        return 0;
    }

    final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
    final int power = n - (int) d;

    final double magnitude = Math.pow(10, power);
    final long shifted = Math.round(num*magnitude);
    return shifted/magnitude;
}

2
मेरे उत्तर को स्वीकार करने के लिए धन्यवाद। मुझे सिर्फ एहसास हुआ कि सवाल के एक साल बाद मेरा जवाब आया है। यह एक कारण है कि स्टैकओवरफ्लो इतना ठंडा क्यों है। आप उपयोगी जानकारी पा सकते हैं!
पाइरोलॉजिकल

2
ध्यान दें कि यह गोल सीमा के करीब मूल्यों के लिए थोड़ा विफल हो सकता है। उदाहरण के लिए 1.255 से 3 महत्वपूर्ण अंकों की गोलाई में 1.26 रिटर्न चाहिए लेकिन 1.25 रिटर्न। ऐसा इसलिए है क्योंकि १.२५५ * १००.० १२५.४ ९९९९ है ... लेकिन जब युगल के साथ काम करने की उम्मीद की जाती है
cquezel

वाह, मुझे पता है कि यह पुराना है, लेकिन मैं इसका उपयोग करने की कोशिश कर रहा हूं। मेरे पास एक फ्लोट है जिसे मैं 3 महत्वपूर्ण आंकड़े प्रदर्शित करना चाहता हूं। यदि फ्लोट का मान 1.0 है, तो मैं आपकी विधि को कॉल करता हूं, लेकिन यह अभी भी 1.0 के रूप में रिटर्न करता है, भले ही मैंने फ्लोट को डबल के रूप में रखा हो। मैं चाहता हूं कि यह 1 के रूप में लौटे। कोई विचार?
स्टीव डब्ल्यू

3
यह जावा स्निपेट आधिकारिक एंड्रॉइड उदाहरण android.googlesource.com/platform/development/+/fcf4286/samples/…
जिज्ञासु सैम

1
अच्छा नहीं। Num = -7999999.999999992 और n = 2 रिटर्न -7999999.999999999 के लिए लेकिन 800800 होना चाहिए।
डंकन कलवर्ट

16

यहाँ एक छोटा और मीठा जावास्क्रिप्ट कार्यान्वयन है:

function sigFigs(n, sig) {
    var mult = Math.pow(10, sig - Math.floor(Math.log(n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
}

alert(sigFigs(1234567, 3)); // Gives 1230000
alert(sigFigs(0.06805, 3)); // Gives 0.0681
alert(sigFigs(5, 3)); // Gives 5

लेकिन 12.1257 12.126 देता है
प्योरोलॉजिकल ऑक्ट

1
अच्छा जवाब Ates। शायद 0 पर लौटने के लिए एक ट्रिगर जोड़ें n==0:)
sscirrus

इसके Math.log(n) / Math.LN10बजाय करने के लिए एक कारण है Math.log10(n)?
ली

1
@Lee developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… "यह एक नई तकनीक है, जो ECMAScript 2015 (ES6) मानक का हिस्सा है।" तो, मूल रूप से, संगतता मुद्दों।
एतेस गोरल

क्या मुझे कुछ याद आ रहा है, या क्या यह उत्तर मान लेता है Math.floor(x) == Math.ceil(x) - 1? क्योंकि यह नहीं है जब xएक पूर्णांक है। मुझे लगता है कि powफ़ंक्शन का दूसरा तर्क होना चाहिए sig - Math.ceil(Math.log(n) / Math.LN10)(या सिर्फ उपयोग Math.log10)
पॉल

15

सारांश:

double roundit(double num, double N)
{
    double d = log10(num);
    double power;
    if (num > 0)
    {
        d = ceil(d);
        power = -(d-N);
    }
    else
    {
        d = floor(d); 
        power = -(d-N);
    }

    return (int)(num * pow(10.0, power) + 0.5) * pow(10.0, -power);
}

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

हम पहले करने के लिए लॉग का उपयोग कर सकते हैं।

log 1239451 = 6.09
log 12.1257 = 1.08
log 0.0681  = -1.16

तो संख्या> 0 के लिए, लॉग के छत को लें। संख्या <0 के लिए, लॉग का फर्श लें।

अब हमारे पास अंक है d: 7 पहले मामले में, 2 में 2, -2 में 3।

हमें (d-N)वें अंक को राउंड करना होगा । कुछ इस तरह:

double roundedrest = num * pow(10, -(d-N));

pow(1239451, -4) = 123.9451
pow(12.1257, 1)  = 121.257
pow(0.0681, 4)   = 681

फिर मानक गोलाई की बात करें:

roundedrest = (int)(roundedrest + 0.5);

और पूर्ववत करें।

roundednum = pow(roundedrest, -(power))

बिजली कहाँ ऊपर गणना शक्ति है।


सटीकता के बारे में: वास्तव में प्योरोलॉजिकल का जवाब वास्तविक परिणाम के करीब है। लेकिन ध्यान दें कि आप किसी भी मामले में ठीक 12.1 का प्रतिनिधित्व नहीं कर सकते हैं। यदि आप उत्तर इस प्रकार हैं:

System.out.println(new BigDecimal(n));

उत्तर हैं:

Pyro's: 12.0999999999999996447286321199499070644378662109375
Mine: 12.10000000000000142108547152020037174224853515625
Printing 12.1 directly: 12.0999999999999996447286321199499070644378662109375

तो, पाइरो के जवाब का उपयोग करें!


1
यह एल्गोरिथ्म फ़्लोटिंग पॉइंट त्रुटियों के लिए प्रवण लगता है। जब जावास्क्रिप्ट के साथ लागू किया जाता है, तो मुझे मिलता है: 0.06805 -> 0.06810000000000001 और 12.1 -> 12.100000000000001
एट्स गोरल

12.1 अपने आप फ्लोटिंग पॉइंट का उपयोग करके सही प्रतिनिधित्व नहीं किया जा सकता है - यह इस एल्गोरिथम का परिणाम नहीं है।
क्लोडिउ

1
जावा में यह कोड 12.100000000000001 का उत्पादन करता है और यह 64-बिट डबल्स का उपयोग कर रहा है जो कि 12.1 को बिल्कुल प्रस्तुत कर सकता है।
प्योरोलॉजिकल ऑक्ट

4
यह 64 बिट या 128 बिट है तो कोई बात नहीं। आप 2 की शक्तियों का एक सीमित राशि का उपयोग करके 1/10 अंश का प्रतिनिधित्व नहीं कर सकते हैं, और यह है कि फ्लोटिंग पॉइंट संख्या का प्रतिनिधित्व कैसे किया जाता है
क्लाउडी

2
उन लोगों के लिए, जो मूल रूप से पाइरोलॉजिकल का जवाब है, मेरी तुलना में अधिक सटीक है ताकि फ्लोटिंग पॉइंट नंबर प्रिंटिंग एल्गोरिथ्म '12 .1 'के बजाय '12 .100000000000001' हो। उनका जवाब बेहतर है, यहां तक ​​कि मैं तकनीकी रूप से सही था कि आप '12 .1 'का प्रतिनिधित्व नहीं कर सकते।
क्लाउडी

10

"लघु और मधुर" जावास्क्रिप्ट कार्यान्वयन नहीं है

Number(n).toPrecision(sig)

जैसे

alert(Number(12345).toPrecision(3)

?

क्षमा करें, मैं यहां मुखर नहीं हो रहा हूं, यह सिर्फ इतना है कि जावास्क्रिप्ट में क्लाउडीयू और .toPreults से "राउंडिट" फ़ंक्शन का उपयोग करने से मुझे अलग-अलग परिणाम मिलते हैं लेकिन केवल अंतिम अंक के चक्कर में।

जावास्क्रिप्ट:

Number(8.14301).toPrecision(4) == 8.143

नेट

roundit(8.14301,4) == 8.144

1
Number(814301).toPrecision(4) == "8.143e+5"। यदि आप इसे उपयोगकर्ताओं को दिखा रहे हैं तो आमतौर पर आप जो चाहते हैं, वह नहीं।
ज़ाज़

बहुत सच्चा जोश हाँ, मैं आम तौर पर .toPreaches () केवल दशमलव संख्याओं के लिए और स्वीकृत उत्तर (संपादित करने के साथ) का उपयोग / समीक्षा आपकी व्यक्तिगत आवश्यकताओं के अनुसार की जानी चाहिए।
जस्टिन विगनेल

8

प्योरोलॉजिकल (बहुत अच्छा!) समाधान में अभी भी एक मुद्दा है। जावा में अधिकतम दोहरा मूल्य 10 ^ 308 के आदेश पर है, जबकि न्यूनतम मूल्य 10 ^ -324 के आदेश पर है। इसलिए, जब आप roundToSignificantFiguresदस में से कुछ शक्तियों के भीतर फ़ंक्शन को लागू करते हैं, तो आप परेशानी में पड़ सकते हैं Double.MIN_VALUE। उदाहरण के लिए, जब आप कॉल करते हैं

roundToSignificantFigures(1.234E-310, 3);

तब चर powerका मान 3 - (-309) = 312 magnitudeहोगा । नतीजतन, चर बन जाएगा Infinity, और यह तब से सभी कचरा है। सौभाग्य से, यह एक दुर्गम समस्या नहीं है: यह केवल कारक है magnitude जो अतिप्रवाह है। उत्पाद वास्तव में क्या मायने रखता है num * magnitude, और यह अतिप्रवाह नहीं है। इसे हल करने का एक तरीका कारक द्वारा गुणन magintudeको दो चरणों में तोड़ना है :


 public static double roundToNumberOfSignificantDigits(double num, int n) {

    final double maxPowerOfTen = Math.floor(Math.log10(Double.MAX_VALUE));

    if(num == 0) {
        return 0;
    }

    final double d = Math.ceil(Math.log10(num < 0 ? -num: num));
    final int power = n - (int) d;

    double firstMagnitudeFactor = 1.0;
    double secondMagnitudeFactor = 1.0;
    if (power > maxPowerOfTen) {
        firstMagnitudeFactor = Math.pow(10.0, maxPowerOfTen);
        secondMagnitudeFactor = Math.pow(10.0, (double) power - maxPowerOfTen);
    } else {
        firstMagnitudeFactor = Math.pow(10.0, (double) power);
    }

    double toBeRounded = num * firstMagnitudeFactor;
    toBeRounded *= secondMagnitudeFactor;

    final long shifted = Math.round(toBeRounded);
    double rounded = ((double) shifted) / firstMagnitudeFactor;
    rounded /= secondMagnitudeFactor;
    return rounded;
}


6

इस जावा समाधान के बारे में कैसे:

डबल राउंडटेसिफिकंटफिगर (डबल संख्या, इंट सटीक) {
 नया BigDecimal (संख्या) वापस करें
            । आसपास
            .doubleValue (); 
}

3

यहां Ates 'जावास्क्रिप्ट का एक संशोधित संस्करण है जो नकारात्मक संख्याओं को संभालता है।

function sigFigs(n, sig) {
    if ( n === 0 )
        return 0
    var mult = Math.pow(10,
        sig - Math.floor(Math.log(n < 0 ? -n: n) / Math.LN10) - 1);
    return Math.round(n * mult) / mult;
 }

2

यह 5 साल देर से आया, लेकिन हालांकि मैं अभी भी उसी मुद्दे वाले अन्य लोगों के लिए साझा करूंगा। मुझे यह पसंद है क्योंकि यह सरल है और कोड पक्ष पर कोई गणना नहीं है। अधिक जानकारी के लिए महत्वपूर्ण आंकड़े प्रदर्शित करने के लिए निर्मित विधियों को देखें ।

यदि आप इसे प्रिंट करना चाहते हैं तो यह है।

public String toSignificantFiguresString(BigDecimal bd, int significantFigures){
    return String.format("%."+significantFigures+"G", bd);
}

यह है यदि आप इसे बदलना चाहते हैं:

public BigDecimal toSignificantFigures(BigDecimal bd, int significantFigures){
    String s = String.format("%."+significantFigures+"G", bd);
    BigDecimal result = new BigDecimal(s);
    return result;
}

यहां इसका एक उदाहरण कार्रवाई में है:

BigDecimal bd = toSignificantFigures(BigDecimal.valueOf(0.0681), 2);

यह वैज्ञानिक संकेतन में "बड़ी" संख्या प्रदर्शित करेगा, जैसे 15k 1.5e04।
मैट

2

जावास्क्रिप्ट:

Number( my_number.toPrecision(3) );

Numberफंक्शन फॉर्म के उत्पादन में बदल जाएगा "8.143e+5"करने के लिए "814300"


1

क्या आपने इसे हाथ से करने के तरीके को ठीक से कोड करने की कोशिश की है?

  1. संख्या को एक स्ट्रिंग में बदलें
  2. स्ट्रिंग की शुरुआत में, अंकों की गणना करें - अग्रणी शून्य महत्वपूर्ण नहीं हैं, बाकी सब कुछ है।
  3. जब आप "nth" अंक पर पहुँचते हैं, तो अगले अंक पर आगे बढ़ते हैं और यदि यह 5 या उससे अधिक है, तो राउंड अप करें।
  4. शून्य से सभी अनुगामी अंकों को बदलें।

1

[सही, 2009-10-26]

अनिवार्य रूप से, एन महत्वपूर्ण आंशिक अंकों के लिए:

• संख्या को 10 N से गुणा करें।
0.5 जोड़ें
• अंश अंकों को काटें (अर्थात परिणाम को पूर्णांक में काटें)
• 10 N से विभाजित करें

एन महत्वपूर्ण अभिन्न (गैर-भिन्नात्मक) अंकों के लिए:

• संख्या को 10 N से विभाजित करें
• 0.5 जोड़ें
। अंश अंकों को काटें (यानी परिणाम को पूर्णांक में काटें)
• 10 N से गुणा करें

आप इसे किसी भी कैलकुलेटर पर कर सकते हैं, उदाहरण के लिए, जिसमें "INT" (पूर्णांक ट्रंकेशन) ऑपरेटर है।


नहीं। प्रश्न फिर से पढ़ें। 1239451 आपके एल्गोरिथ्म का उपयोग करते हुए 3 सिग अंजीर के साथ गलत तरीके से उपज होगी 123951
18

हां, मैंने इसे अंकों की एक भिन्नात्मक संख्या (दशमलव बिंदु के दाईं ओर) बनाम अंकों की एक अभिन्न संख्या (बाईं ओर) के बीच अंतर करने के लिए सही किया ।
डेविड आर ट्रिब्बल

1
/**
 * Set Significant Digits.
 * @param value value
 * @param digits digits
 * @return
 */
public static BigDecimal setSignificantDigits(BigDecimal value, int digits) {
    //# Start with the leftmost non-zero digit (e.g. the "1" in 1200, or the "2" in 0.0256).
    //# Keep n digits. Replace the rest with zeros.
    //# Round up by one if appropriate.
    int p = value.precision();
    int s = value.scale();
    if (p < digits) {
        value = value.setScale(s + digits - p); //, RoundingMode.HALF_UP
    }
    value = value.movePointRight(s).movePointLeft(p - digits).setScale(0, RoundingMode.HALF_UP)
        .movePointRight(p - digits).movePointLeft(s);
    s = (s > (p - digits)) ? (s - (p - digits)) : 0;
    return value.setScale(s);
}

1

यहाँ Visual Basic.NET में प्योरोलॉजिकल (वर्तमान में शीर्ष उत्तर) कोड है, किसी को भी इसकी आवश्यकता होनी चाहिए:

Public Shared Function roundToSignificantDigits(ByVal num As Double, ByVal n As Integer) As Double
    If (num = 0) Then
        Return 0
    End If

    Dim d As Double = Math.Ceiling(Math.Log10(If(num < 0, -num, num)))
    Dim power As Integer = n - CInt(d)
    Dim magnitude As Double = Math.Pow(10, power)
    Dim shifted As Double = Math.Round(num * magnitude)
    Return shifted / magnitude
End Function

0

यह एक है जो मैं VB में आया था:

Function SF(n As Double, SigFigs As Integer)
    Dim l As Integer = n.ToString.Length
    n = n / 10 ^ (l - SigFigs)
    n = Math.Round(n)
    n = n * 10 ^ (l - SigFigs)
    Return n
End Function


0

मुझे गो में इसकी आवश्यकता थी, जो कि गो मानक पुस्तकालय की कमी math.Round()(go1.10 से पहले) से थोड़ा जटिल था । इसलिए मुझे भी कोड़ा मारना पड़ा। यहाँ मेरा अनुवाद है प्योरोलॉजिकल का उत्कृष्ट उत्तर :

// TODO: replace in go1.10 with math.Round()
func round(x float64) float64 {
    return float64(int64(x + 0.5))
}

// SignificantDigits rounds a float64 to digits significant digits.
// Translated from Java at https://stackoverflow.com/a/1581007/1068283
func SignificantDigits(x float64, digits int) float64 {
    if x == 0 {
        return 0
    }

    power := digits - int(math.Ceil(math.Log10(math.Abs(x))))
    magnitude := math.Pow(10, float64(power))
    shifted := round(x * magnitude)
    return shifted / magnitude
}

यह एक रहस्य है! लेकिन मुझे इसमें कोई त्रुटि या समस्या नहीं मिल रही है। यहाँ क्या चल रहा है?
माइकल हैम्पटन

0

आप इन सभी गणनाओं को 10 की शक्तियों के साथ करने से बच सकते हैं।

FloatToStrF आपको (अन्य चीजों के बीच) आउटपुट वैल्यू में सटीक (महत्वपूर्ण संख्याओं की संख्या) चुनने की अनुमति देता है (जो एक स्ट्रिंग होगी)। बेशक, आप इसके बाद StrToFloat को एक फ्लोट के रूप में अपने गोल मूल्य को प्राप्त करने के लिए आवेदन कर सकते हैं।

यहाँ देखें:

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_FloatToStrF@Extended@TFloatFormat@Integer@Integer.html


-1
public static double roundToSignificantDigits(double num, int n) {
    return Double.parseDouble(new java.util.Formatter().format("%." + (n - 1) + "e", num).toString());
}

यह कोड इनबिल्ट फॉर्मेटिंग फंक्शन का उपयोग करता है जो एक राउंडिंग फंक्शन में बदल जाता है

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