如何格式化保留两位小数的数字?

Cod*_*ist 5 number-formatting decimalformat kotlin

这就是我正在做的以显示两位小数的金额。它工作正常,但我想知道这是否正确或者这样做有什么缺点以及更好的方法是什么

\n

我想格式化“您的价格”和“MRP”的金额。我怎样才能做到这一点?

\n
        holder.itemView.tv_dashboard_item_title.text = model.title\n        holder.itemView.tv_dashboard_item_price.text = "Your Price \xe2\x82\xb9${model.price}"\n        holder.itemView.tv_dashboard_item_mrp.text = "MRP \xe2\x82\xb9${model.mrp}"\n        val mrp:Double? = model.mrp\n        val price: Double? = model.price\n        val save=DecimalFormat("#,##0.00")\n        val save2: Double = mrp!! - price!!\n        val saves=save.format(save2)\n\n        holder.itemView.tv_dashboard_item_you_save.text = "You Save \xe2\x82\xb9  $saves"\n
Run Code Online (Sandbox Code Playgroud)\n

谢谢。

\n

编辑

\n

修改后的代码。

\n
    val decFormat = DecimalFormat("#,##0.00")\n    holder.itemView.tv_dashboard_item_title.text = model.title\n    val mrp: BigDecimal = model.mrp.toBigDecimal()\n    val price: BigDecimal = model.price.toBigDecimal()\n\n    val save: BigDecimal = mrp - price\n    val saveAmount = decFormat.format(save)\n\n    holder.itemView.tv_dashboard_item_price.text = decFormat.format(price)\n    holder.itemView.tv_dashboard_item_mrp.text = decFormat.format(mrp)\n    holder.itemView.tv_dashboard_item_you_save.text = "You Save \xe2\x82\xb9  $saveAmount"\n
Run Code Online (Sandbox Code Playgroud)\n

编辑2

\n

以下是模型类Product.kt

\n
@Parcelize\ndata class Product(\n    val user_id: String = "",\n    val user_name: String = "",\n    val title: String = "",\n    val mrp: BigDecimal= "0.00".toBigDecimal(),\n    val price: BigDecimal = "0.00".toBigDecimal(),\n    val description: String = "",\n    val stock_quantity: String = "",\n    val image: String = "",\n    var brand_name:String="",\n    var manufacturer:String="",\n    var main_category:String="",\n    var sub_category:String="",\n    var product_id: String = "",\n) : Parcelable\n
Run Code Online (Sandbox Code Playgroud)\n

AddProductActivity.kt上传产品详细信息的功能

\n
   private fun uploadProductDetails() {\n        val username =\n            this.getSharedPreferences(Constants.TRAD_PREFERENCES, Context.MODE_PRIVATE)\n                .getString(Constants.LOGGED_IN_USERNAME, "")!!\n\n        val product = Product(\n            FirestoreClass().getCurrentUserID(),\n            username,\n            et_product_title.text.toString().trim { it <= ' ' },\n            et_product_mrp.text.toString().toBigDecimal(),\n            et_product_price.text.toString().toBigDecimal(),\n            et_product_description.text.toString().trim { it <= ' ' },\n            et_product_quantity.text.toString().trim { it <= ' ' },\n            mProductImageURL,\n            et_product_brand_name.text.toString().trim { it <= ' ' },\n            et_product_manufacturer.text.toString().trim { it <= ' ' },\n            et_product_main_category.text.toString().trim { it <= ' ' },\n            et_product_sub_category.text.toString().trim { it <= ' ' },\n        )\n\n        FirestoreClass().uploadProductDetails(this@AddProductActivity, product)\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

Logcat

\n
   --------- beginning of crash\n2021-06-19 18:36:11.605 6674-6674/com.trad E/AndroidRuntime: FATAL EXCEPTION: main\n    Process: com.trad, PID: 6674\n    java.lang.IllegalArgumentException: Could not serialize object. Numbers of type BigDecimal are not supported, please use an int, long, float or double (found in field 'mrp')\n        at com.google.firebase.firestore.util.CustomClassMapper.serializeError(CustomClassMapper.java:555)\n        at com.google.firebase.firestore.util.CustomClassMapper.serialize(CustomClassMapper.java:122)\n        at com.google.firebase.firestore.util.CustomClassMapper.access$400(CustomClassMapper.java:54)\n        at com.google.firebase.firestore.util.CustomClassMapper$BeanMapper.serialize(CustomClassMapper.java:902)\n        at com.google.firebase.firestore.util.CustomClassMapper.serialize(CustomClassMapper.java:178)\n        at com.google.firebase.firestore.util.CustomClassMapper.serialize(CustomClassMapper.java:104)\n        at com.google.firebase.firestore.util.CustomClassMapper.convertToPlainJavaTypes(CustomClassMapper.java:78)\n        at com.google.firebase.firestore.UserDataReader.convertAndParseDocumentData(UserDataReader.java:231)\n        at com.google.firebase.firestore.UserDataReader.parseMergeData(UserDataReader.java:87)\n        at com.google.firebase.firestore.DocumentReference.set(DocumentReference.java:166)\n        at com.trad.firestore.FirestoreClass.uploadProductDetails(FirestoreClass.kt:246)\n        at com.trad.ui.activities.AddProductActivity.uploadProductDetails(AddProductActivity.kt:280)\n        at com.trad.ui.activities.AddProductActivity.imageUploadSuccess(AddProductActivity.kt:254)\n        at com.trad.firestore.FirestoreClass$uploadImageToCloudStorage$1$1.onSuccess(FirestoreClass.kt:212)\n        at com.trad.firestore.FirestoreClass$uploadImageToCloudStorage$1$1.onSuccess(FirestoreClass.kt:27)\n        at com.google.android.gms.tasks.zzn.run(com.google.android.gms:play-services-tasks@@17.2.0:4)\n        at android.os.Handler.handleCallback(Handler.java:938)\n        at android.os.Handler.dispatchMessage(Handler.java:99)\n        at android.os.Looper.loop(Looper.java:246)\n        at android.app.ActivityThread.main(ActivityThread.java:8512)\n        at java.lang.reflect.Method.invoke(Native Method)\n        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)\n        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)\n
Run Code Online (Sandbox Code Playgroud)\n

gid*_*dds 6

使用 aDecimalFormat是格式化数字的好方法。

\n

然而,这里有一个更深层次的问题,那就是你永远不应该使用 Float 或 Double 来存储需要精确的值,例如 Money

\n

这是因为浮点数和双精度数存储为二进制分数,而不是十进制分数。\xe2\x80\x82 正如你无法将 1/3 精确地表示为任何有限长度的小数分数 (0.33333333333\xe2\ x80\xa6),所以你不能将 1/10 精确地表示为二进制分数 (0.0001100110011\xe2\x80\xa6)。\xe2\x80\x82 因此,你想要存储的大多数十进制数字将得到近似值四舍五入到可以存储的最接近的二进制分数。 \xe2\x80\x82 这并不总是显而易见的 \xe2\x80\x94 打印它们时,它们会再次四舍五入到最接近的十进制分数,并且在许多情况下\xe2\x80\x98 恢复\xe2\x80\x99 你想要的数字 \xe2\x80\x94 但有很多情况下它是引人注目的,特别是作为计算结果。

\n

可以在Kotlin REPL中看到效果:

\n
>>> 0.1 + 0.2\nres0: kotlin.Double = 0.30000000000000004\n
Run Code Online (Sandbox Code Playgroud)\n

在本例中,最接近 0.1 和 0.2 的二进制分数相加得到的二进制分数更接近 0.30000000000000004,而不是 0.3。

\n

(StackOverflow 上有许多现有问题讨论此问题,例如此处。)

\n

因此,如果您需要准确的货币值(而且您几乎总是这样做!),那么您应该以其他方式存储它们。\xe2\x80\x82 例如,如果您只需要两位小数(即paise),然后简单地将 paise 的数量存储为整数。\xe2\x80\x82 或者,如果您不需要进行任何计算,则可以将数字存储为字符串(否则这是一个坏主意\xe2 \x80\xa6)。

\n

然而,Kotlin(和 Java)中最通用和灵活的方法是使用BigDecimal . \xe2\x80\x82 它在内部使用小数分数来精确地表示任何十进制数字,达到您需要的任何精度,并且您可以轻松地进行计算和其他操纵。

\n

在 Java 中,使用它是笨拙且冗长的,但是 Kotlin 的运算符重载使其变得非常自然,例如:

\n
>>> val p1 = "0.1".toBigDecimal()\n>>> val p2 = "0.2".toBigDecimal()\n>>> p1 + p2\nres3: java.math.BigDecimal = 0.3\n
Run Code Online (Sandbox Code Playgroud)\n

DecimalFormat也支持它:

\n
>>> java.text.DecimalFormat("#,##0.00").format(p1 + p2)\nres4: kotlin.String! = 0.30\n
Run Code Online (Sandbox Code Playgroud)\n

(注意:不要Float 或 Double 创建 BigDecimal,因为损坏已经造成。\xe2\x80\x82 如果您有整数值,则从整数类型开始,例如 Int 或 Long;否则,您需要从字符串开始才能获得准确的值。)

\n