क्या कोई फ़ंक्शन है जो एक डबल को छोटा या गोल कर सकता है? मेरे कोड में एक बिंदु पर मुझे एक संख्या पसंद होगी: 1.23456789
को गोल किया जाएगा1.23
क्या कोई फ़ंक्शन है जो एक डबल को छोटा या गोल कर सकता है? मेरे कोड में एक बिंदु पर मुझे एक संख्या पसंद होगी: 1.23456789
को गोल किया जाएगा1.23
जवाबों:
आप उपयोग कर सकते हैं scala.math.BigDecimal
:
BigDecimal(1.23456789).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
कई अन्य राउंडिंग मोड हैं , जो दुर्भाग्य से वर्तमान में बहुत अच्छी तरह से प्रलेखित नहीं हैं (हालांकि उनके जावा समकक्ष हैं )।
"%.2f".format(x).toDouble
उस मामले में सिफारिश करूंगा । केवल 2x धीमा, और आपको केवल एक पुस्तकालय का उपयोग करना होगा जिसे आप पहले से जानते हैं।
scala> "%.2f".format(0.714999999999).toDouble
res13: Double = 0.71
लेकिन scala> "%.2f".format(0.715).toDouble
res14: Double = 0.72
।
यहाँ BigDecimals के बिना एक और समाधान है
छोटा करें:
(math floor 1.23456789 * 100) / 100
गोल:
(math rint 1.23456789 * 100) / 100
या किसी भी डबल एन और सटीक पी के लिए:
def truncateAt(n: Double, p: Int): Double = { val s = math pow (10, p); (math floor n * s) / s }
इसी तरह से राउंडिंग फ़ंक्शन के लिए किया जा सकता है, इस बार करी का उपयोग करके:
def roundAt(p: Int)(n: Double): Double = { val s = math pow (10, p); (math round n * s) / s }
जो अधिक पुन: प्रयोज्य है, उदाहरण के लिए, जब धनराशि को गोल किया जाता है तो निम्नलिखित का उपयोग किया जा सकता है:
def roundAt2(n: Double) = roundAt(2)(n)
NaN
है कि यह गलत परिणाम नहीं है?
floor
यह है truncateAt(1.23456789, 8)
वापस आ जाएगी 1.23456788
, जबकि roundAt(1.23456789, 8)
का सही मूल्य वापस आ जाएगी1.23456789
चूंकि किसी ने भी %
ऑपरेटर का उल्लेख नहीं किया है, यहाँ आता है। यह केवल काट-छाँट करता है, और आप रिटर्न वैल्यू पर भरोसा नहीं कर सकते कि फ्लोटिंग पॉइंट अशुद्धि है, लेकिन यह आसान है:
scala> 1.23456789 - (1.23456789 % 0.01)
res4: Double = 1.23
26.257391515826225 - 0.057391515826223094 = 26.200000000000003
कैसा रहेगा :
val value = 1.4142135623730951
//3 decimal places
println((value * 1000).round / 1000.toDouble)
//4 decimal places
println((value * 10000).round / 10000.toDouble)
((1.949 * 1000).toInt - ((1.949 * 1000).toInt % 10)) / 1000.toDouble
हालांकि यह बहुत अधिक परीक्षण नहीं किया। यह कोड 2 दशमलव स्थानों को करेगा।
संपादित करें: @ryryguy ने इंगित की गई समस्या को ठीक किया। (धन्यवाद!)
यदि आप चाहते हैं कि यह तेज़ हो, तो काइटो के पास सही विचार है। math.pow
हालांकि धीमा है। किसी भी मानक उपयोग के लिए आप पुनरावर्ती फ़ंक्शन के साथ बेहतर हैं:
def trunc(x: Double, n: Int) = {
def p10(n: Int, pow: Long = 10): Long = if (n==0) pow else p10(n-1,pow*10)
if (n < 0) {
val m = p10(-n).toDouble
math.round(x/m) * m
}
else {
val m = p10(n).toDouble
math.round(x*m) / m
}
}
यदि आप Long
(यानी 18 अंक) की सीमा के भीतर हैं, तो यह लगभग 10x तेज़ है , इसलिए आप 10 ^ 18 और 10 ^ -18 के बीच कहीं भी चक्कर लगा सकते हैं।
scala> def r5(x:Double) = math.round(x*100000)*0.000001; r5(0.23515)
=>> res12: Double = 0.023514999999999998
। इसके बजाय महत्व से विभाजित करें:math.round(x*100000)/100000.0
p10
एक सरणी लुकअप के साथ पुनरावर्ती फ़ंक्शन को बदलने के लिए भी उपयोगी हो सकता है : सरणी लगभग 200 बाइट्स द्वारा मेमोरी की खपत में वृद्धि करेगी, लेकिन संभवतः प्रति कॉल कई पुनरावृत्तियों को बचाएगी।
आप निहित वर्गों का उपयोग कर सकते हैं:
import scala.math._
object ExtNumber extends App {
implicit class ExtendedDouble(n: Double) {
def rounded(x: Int) = {
val w = pow(10, x)
(n * w).toLong.toDouble / w
}
}
// usage
val a = 1.23456789
println(a.rounded(2))
}
जो लोग रुचि रखते हैं, उनके लिए सुझाए गए समाधानों के लिए यहां कुछ समय दिया गया है ...
Rounding
Java Formatter: Elapsed Time: 105
Scala Formatter: Elapsed Time: 167
BigDecimal Formatter: Elapsed Time: 27
Truncation
Scala custom Formatter: Elapsed Time: 3
ट्रडनेशन सबसे तेज़ है, इसके बाद बिगडेसीमल है। ध्यान रखें कि ये परीक्षण किसी भी बेंचमार्किंग टूल का उपयोग न करते हुए नॉर्मा स्कैला निष्पादन चलाने के लिए किए गए थे।
object TestFormatters {
val r = scala.util.Random
def textFormatter(x: Double) = new java.text.DecimalFormat("0.##").format(x)
def scalaFormatter(x: Double) = "$pi%1.2f".format(x)
def bigDecimalFormatter(x: Double) = BigDecimal(x).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
def scalaCustom(x: Double) = {
val roundBy = 2
val w = math.pow(10, roundBy)
(x * w).toLong.toDouble / w
}
def timed(f: => Unit) = {
val start = System.currentTimeMillis()
f
val end = System.currentTimeMillis()
println("Elapsed Time: " + (end - start))
}
def main(args: Array[String]): Unit = {
print("Java Formatter: ")
val iters = 10000
timed {
(0 until iters) foreach { _ =>
textFormatter(r.nextDouble())
}
}
print("Scala Formatter: ")
timed {
(0 until iters) foreach { _ =>
scalaFormatter(r.nextDouble())
}
}
print("BigDecimal Formatter: ")
timed {
(0 until iters) foreach { _ =>
bigDecimalFormatter(r.nextDouble())
}
}
print("Scala custom Formatter (truncation): ")
timed {
(0 until iters) foreach { _ =>
scalaCustom(r.nextDouble())
}
}
}
}
...truncate or round a Double
।
doubleParts.tail
स्ट्रिंग्स के साथ और कॉनैट के पहले दो वर्ण प्राप्त करें ""। और doubleParts. head
डबल करने के लिए पार्स।
toString.split(".")
और doubleParts.head/tail
सुझाव भी अतिरिक्त सरणी आवंटन और स्ट्रिंग संघनन से पीड़ित हो सकते हैं। हालांकि यह सुनिश्चित करने के लिए परीक्षण करने की आवश्यकता होगी।
हाल ही में, मुझे इसी तरह की समस्या का सामना करना पड़ा और मैंने इसे निम्नलिखित दृष्टिकोण का उपयोग करके हल किया
def round(value: Either[Double, Float], places: Int) = {
if (places < 0) 0
else {
val factor = Math.pow(10, places)
value match {
case Left(d) => (Math.round(d * factor) / factor)
case Right(f) => (Math.round(f * factor) / factor)
}
}
}
def round(value: Double): Double = round(Left(value), 0)
def round(value: Double, places: Int): Double = round(Left(value), places)
def round(value: Float): Double = round(Right(value), 0)
def round(value: Float, places: Int): Double = round(Right(value), places)
मैं इस एसओ मुद्दे का इस्तेमाल किया । मेरे पास फ्लोट \ डबल और अंतर्निहित \ स्पष्ट दोनों विकल्पों के लिए अतिभारित कार्य हैं। ध्यान दें, आपको ओवरलोड कार्यों के मामले में स्पष्ट रूप से रिटर्न प्रकार का उल्लेख करना होगा।
स्काला f
इंटरपोलर का उपयोग करना वास्तव में बहुत आसान है - https://docs.scala-lang.org/overviews/core/string-interpolation.html
मान लीजिए कि हम 2 दशमलव स्थानों तक चक्कर लगाना चाहते हैं:
scala> val sum = 1 + 1/4D + 1/7D + 1/10D + 1/13D
sum: Double = 1.5697802197802198
scala> println(f"$sum%1.2f")
1.57
यदि आप प्रदर्शन के बारे में परवाह करते हैं तो मैं BigDecimal का उपयोग नहीं करूंगा। BigDecimal संख्याओं को स्ट्रिंग में परिवर्तित करता है और फिर इसे फिर से पार्स करता है:
/** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */
def decimal(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc)
जैसा कि काइटो ने सुझाव दिया था कि मैं गणित में हेरफेर करने जा रहा हूं ।
तुम कर सकते हो:Math.round(<double precision value> * 100.0) / 100.0
लेकिन Math.round सबसे तेज़ है लेकिन यह कोने के मामलों में या तो बहुत अधिक संख्या में दशमलव स्थानों (जैसे राउंड (1000.0d, 17)) या बड़े पूर्णांक वाले भाग (जैसे राउंड (90080070060.1d, 9) के साथ बुरी तरह से टूट जाता है )।
Bigdecimal का उपयोग करें यह थोड़ा अक्षम है क्योंकि यह मूल्यों को स्ट्रिंग में परिवर्तित करता है लेकिन अधिक मध्ययुगीन:
BigDecimal(<value>).setScale(<places>, RoundingMode.HALF_UP).doubleValue()
गोलाई मोड की अपनी प्राथमिकता का उपयोग करें।
यदि आप उत्सुक हैं और अधिक विस्तार से जानना चाहते हैं कि ऐसा क्यों होता है तो आप इसे पढ़ सकते हैं: