স্কেলা দ্বিগুণ এবং যথার্থতা


117

এমন কোনও ফাংশন রয়েছে যা একটি ডাবল কেটে বা গোল করতে পারে? আমার কোডের এক পর্যায়ে আমি একটি নম্বর চাই: 1.23456789গোল করতে হবে to1.23


9
সব উত্তর দেখার পরে আমি অনুমান করি যে সংক্ষিপ্ত উত্তরটি নেই? :)
মার্সেলাস ওয়ালেস

4
@ গেভার্গ আপনি আমাকে হাসাহাসি করেছেন অন্যান্য সংখ্যার ভারী ভাষা থেকে আমি স্কালায় নতুন এবং আমার চোয়াল প্রায় এই থ্রেডটি পড়ে ফ্লোরে আঘাত করেছিল। এটি একটি প্রোগ্রামিং ভাষার জন্য উন্মাদ অবস্থা affairs
এলে

উত্তর:


150

আপনি ব্যবহার করতে পারেন scala.math.BigDecimal:

BigDecimal(1.23456789).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble

অন্যান্য কয়েকটি গোলাকার মোড রয়েছে , যা দুর্ভাগ্যক্রমে বর্তমানে খুব ভালভাবে নথিভুক্ত করা হয়নি (যদিও তাদের জাভা সমতুল্য )।


5
আমি সম্ভবত বলব। গ্রিড বা ফিনান্স জড়িত যে কোনও কিছুর জন্য রাউন্ডিং এবং পারফরম্যান্সের প্রয়োজন হতে পারে।
রেক্স কের

27
আমি মনে করি এমন কিছু লোক আছে যাদের জন্য একটি ক্লানকি লাইব্রেরিতে দীর্ঘ কল করা সহজ গণিতের চেয়ে বেশি বোঝা যায়। আমি "%.2f".format(x).toDoubleএই ক্ষেত্রে সুপারিশ করব । কেবল 2x ধীর গতির এবং আপনাকে কেবল এমন একটি লাইব্রেরি ব্যবহার করতে হবে যা আপনি ইতিমধ্যে জানেন।
রেক্স কের

6
@ রেক্সার কের, আপনি এক্ষেত্রে গোল করছেন না ... খালি কাটাচ্ছেন।
জোসে লিয়াল

16
@ জোসেলিয়েল - হু? scala> "%.2f".format(0.714999999999).toDouble res13: Double = 0.71কিন্তু scala> "%.2f".format(0.715).toDouble res14: Double = 0.72
রেক্স কের 18

5
@ রেক্সার কের আমি আপনার স্ট্রিং.ফর্ম্যাট উপায়ে পছন্দ করি তবে লোকাল সা মাইনে (ফিনিশ) তে অবশ্যই রুট লোকাল ঠিক করার জন্য যত্ন নেওয়া উচিত। যেমন "% .2f"। ফর্ম্যাটলোকাল (java.util.Locale.ROOT, x) .toDouble। দেখে মনে হচ্ছে, লোকেলের কারণে ফর্ম্যাটটি ',' ব্যবহার করে যেখানে টুডাবল এটি নিতে সক্ষম হয় না এবং একটি সংখ্যার ফর্ম্যাট এক্সেপশন নিক্ষেপ করে। এটি অবশ্যই আপনার কোডটি চালিত হচ্ছে , যেখানে এটি তৈরি হয়েছে তা নয় based
akauppi

77

এখানে বিগডিসিমালগুলি ছাড়া আর একটি সমাধান solution

truncate:

(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)

8
roundAt2 ডিফ রাউন্ডআউট 2 হওয়া উচিত (এন: ডাবল) = রাউন্ডএট (2) (এন) না?
সি

এটি মনে করে এর জন্য ভুল ফলাফল ফিরে আসে NaN, তাই না?
জঙ্গোরেকি

সঙ্গে সমস্যা floorঅর্থাৎ truncateAt(1.23456789, 8)ফিরে আসবে 1.23456788যখন roundAt(1.23456789, 8)সঠিক মান ফিরে আসবে1.23456789
Todor Kolev

35

যেহেতু কেউ %এখনও অপারেটরটির কথা উল্লেখ করেনি, এখানে আসে। এটি কেবল ছাঁটাই করে এবং আপনি ফ্লোটিং পয়েন্টের ভুল ব্যবহার না করে ফেরতের মূল্যের উপর নির্ভর করতে পারবেন না, তবে কখনও কখনও এটি কার্যকরও হয়:

scala> 1.23456789 - (1.23456789 % 0.01)
res4: Double = 1.23

2
এটি আমার নিজের উত্তর হওয়া সত্ত্বেও এটির প্রস্তাব দেবে না: @ রাইরিগুয়ে উল্লিখিত একই ভুলত্রুটিগুলি অন্য উত্তরের মন্তব্যেও এখানে প্রভাবিত করে। জাভা রুট লোকালের সাথে স্ট্রিং.ফর্ম্যাট ব্যবহার করুন (আমি সেখানে সে সম্পর্কে মন্তব্য করব)।
akauppi

এটি সঠিক যদি আপনার কেবলমাত্র মানটি সরবরাহ করতে হয় এবং পরবর্তী ক্রিয়াকলাপগুলিতে কখনই এটি ব্যবহার না করে। ধন্যবাদ
আলেকজান্ডার আরেনদার 21

3
এখানে মজার কিছু: 26.257391515826225 - 0.057391515826223094 = 26.200000000000003
কুবুদি

12

কেমন :

 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 দশমিক জায়গায় করবে।
রবার্ট

7

সম্পাদনা: @ryryguy নির্দেশিত সমস্যাটি ঠিক করেছে। (ধন্যবাদ!)

যদি আপনি এটি দ্রুত হতে চান, কাইটো সঠিক ধারণা আছে। math.powধীর, যদিও। যে কোনও মানক ব্যবহারের জন্য আপনি একটি পুনরাবৃত্ত ফাংশন দিয়ে ভাল off

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 and 18 এবং 10 ^ -18 এর মধ্যে যে কোনও জায়গায় যেতে পারেন।


3
সতর্কতা অবলম্বন করুন, পারস্পরিক ক্রিয়াকলাপ দ্বারা গুণ করা নির্ভরযোগ্যভাবে কাজ করে না, কারণ এটি নির্ভরযোগ্যভাবে ডাবল হিসাবে প্রতিনিধিত্বযোগ্য নয়: scala> def r5(x:Double) = math.round(x*100000)*0.000001; r5(0.23515)==> res12: Double = 0.023514999999999998। পরিবর্তে তাৎপর্য দ্বারা ভাগ করুন:math.round(x*100000)/100000.0
ryryguy

এটি p10অ্যারে লুকোচুরির সাথে পুনরাবৃত্ত ফাংশনটি প্রতিস্থাপন করতেও কার্যকর হতে পারে : অ্যারে মেমরির খরচ প্রায় 200 বাইট বাড়িয়ে দেবে তবে সম্ভবত কল প্রতি একাধিক পুনরাবৃত্তি সংরক্ষণ করবে।
লেবি রামসে

4

আপনি অন্তর্ভুক্ত ক্লাস ব্যবহার করতে পারেন:

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))
}

1
দয়া করে উল্লেখ করুন যে এই পদ্ধতিটি কেবল কাটা কাটা জন্য এবং সঠিকভাবে বৃত্তাকার নয়।
bobo32

4

যারা আগ্রহী তাদের জন্য, প্রস্তাবিত সমাধানগুলির জন্য এখানে কিছু সময় দেওয়া হয়েছে ...

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())
      }
    }
  }

}

1
প্রিয় স্কাল কাস্টম গোল হচ্ছে না, কেবল ছাঁটাই করছে
রবীন্দ্র পায়েল

হুম, ওপি গোল করা বা কাটা কাটা নির্দিষ্ট নয়; ...truncate or round a Double
শেভরিস

তবে আমার মতে রাউন্ডিং ফাংশনগুলির কাটা কাটা কার্যের গতি / সম্পাদনের সময়ের তুলনা করা অপর্যাপ্ত। এজন্য আমি আপনাকে এটি পাঠকের কাছে পরিষ্কার করতে বলেছি যে কাস্টম বৈশিষ্ট্যটি কেবল ছাঁটাই করে। এবং আপনার দ্বারা উল্লিখিত কাটা / কাস্টম ফাংশন আরও সহজ করা যেতে পারে। ভল ডাবল পার্টস = ডাবল। toString.split ("।") এখন প্রথম দুটি অক্ষর doubleParts.tailএবং স্ট্রিং সহ কনক্যাট করুন "" এবং doubleParts. headএবং দ্বিগুণ করতে পার্স।
রবীন্দ্র পায়েল

1
আপডেট হয়েছে, আরও ভাল লাগছে? এছাড়াও আপনার পরামর্শ toString.split(".")এবং doubleParts.head/tailপরামর্শ অতিরিক্ত অ্যারে বরাদ্দ প্লাস স্ট্রিং কনকন্টেশন দ্বারা ভুগতে পারে। যদিও নিশ্চিত হওয়ার জন্য পরীক্ষা করা দরকার।
শেভেরিস

3

সম্প্রতি, আমি একই সমস্যার মুখোমুখি হয়েছি এবং নিম্নলিখিত পদ্ধতির সাহায্যে এটি সমাধান করেছি

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)

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


এছাড়াও, আপনি ম্যাথ.পাওয়ার পরিবর্তে ক্ষমতার জন্য @ রেক্স-কেরারের পদ্ধতিকে ব্যবহার করতে পারেন
খালিদ সাইফুল্লাহ


1

আপনি যদি পারফরম্যান্সের বিষয়ে চিন্তা করেন তবে আমি বিগডিসিমাল ব্যবহার করব না। বিগডিসিমাল সংখ্যাগুলিকে স্ট্রিংয়ে রূপান্তর করে এবং তারপরে আবার পার্স করে:

  /** 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)

কৈতোর পরামর্শ অনুসারে আমি গণিতের হেরফেরগুলিতে আটকে যাচ্ছি ।


0

কিছুটা অদ্ভুত তবে সুন্দর। আমি স্ট্রিং ব্যবহার করি এবং বিগডিসিমাল নয়

def round(x: Double)(p: Int): Double = {
    var A = x.toString().split('.')
    (A(0) + "." + A(1).substring(0, if (p > A(1).length()) A(1).length() else p)).toDouble
}

0

আপনি এটি করতে পারেন: Math.round(<double precision value> * 100.0) / 100.0 তবে ম্যাথ.গ্রাউন্ডটি দ্রুততম তবে এটি কোণার ক্ষেত্রে খুব বেশি সংখ্যক দশমিক স্থানের (যেমন গোলাকার (1000.0 ডি, 17)) বা বৃহত পূর্ণসংখ্যার অংশ (যেমন গোলাকার (90080070060.1 ডি, 9) এর সাথে খারাপভাবে ভেঙে যায় )।

বিগডিসিমাল ব্যবহার করুন এটি কিছুটা অক্ষম হওয়ায় এটি মানগুলিকে স্ট্রিংয়ে রূপান্তর করে তবে আরও স্বস্তি: BigDecimal(<value>).setScale(<places>, RoundingMode.HALF_UP).doubleValue() রাউন্ডিং মোডের আপনার পছন্দ ব্যবহার করুন।

যদি আপনি কৌতূহলী হন এবং আরও কেন জানতে চান তবে কেন এটি হয় আপনি এটি পড়তে পারেন: এখানে চিত্র বর্ণনা লিখুন

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