为什么在 Kotlin 中 "float" 会导致如此多的数据精度损失?

Why so much data precision loss with "float" in Kotlin?

我正在使用 MPAndroidChart 在我的 Android 应用程序中绘制图表。接受 x 轴值和 y 轴值的 "entry()" 函数的声明语法为: entry(float x, float y)

现在,我在 Kotlin 中的 float 问题如下:

我不断从另一个蓝牙设备接收数据,其中一个数据字段是时间戳值(无符号 32 位)。此时间戳值以毫秒为单位,我需要将此值除以 1000 并在 "sec" 中绘制 x 轴值。但是,我在 Kotlin 中使用 "float" 数据类型失去了很多精度。

例如,考虑以下代码:

/**
* You can edit, run, and share this code. 
* play.kotlinlang.org 
*/

import java.text.DecimalFormat;

fun main() {
   var mArrayList:ArrayList<UByte> = ArrayList()
   mArrayList.add(0xFF.toUByte())
   mArrayList.add(0xFF.toUByte())
   mArrayList.add(0xFF.toUByte())
   mArrayList.add(0xFF.toUByte())


   var intInc:UByte = 0.toUByte()
   var mTimeStamp:UInt 
   var mFloatVal:Float 
   var mDoubleVal:Double 

   for(i in 1..10){
       mArrayList.set(3, intInc)
       intInc = intInc.plus(2.toUByte()).toUByte()

       mTimeStamp = mArrayList.get(0).toUInt().shl(24)
       mTimeStamp = mTimeStamp.or(mArrayList.get(1).toUInt().shl(16))
       mTimeStamp = mTimeStamp.or(mArrayList.get(2).toUInt().shl(8))
       mTimeStamp = mTimeStamp.or(mArrayList.get(3).toUInt().shl(0))

       mDoubleVal = mTimeStamp.toDouble()
       mDoubleVal = mDoubleVal.div(1000)
       mFloatVal = mDoubleVal.toFloat()
       println("mTimeSTamp = $mTimeStamp, mDoubleVal = $mDoubleVal, mFloatVal = $mFloatVal")
   }   
}

代码输出:

mTimeSTamp = 4294967040, mDoubleVal = 4294967.04, mFloatVal = 4294967.0
mTimeSTamp = 4294967042, mDoubleVal = 4294967.042, mFloatVal = 4294967.0
mTimeSTamp = 4294967044, mDoubleVal = 4294967.044, mFloatVal = 4294967.0
mTimeSTamp = 4294967046, mDoubleVal = 4294967.046, mFloatVal = 4294967.0
mTimeSTamp = 4294967048, mDoubleVal = 4294967.048, mFloatVal = 4294967.0
mTimeSTamp = 4294967050, mDoubleVal = 4294967.05, mFloatVal = 4294967.0
mTimeSTamp = 4294967052, mDoubleVal = 4294967.052, mFloatVal = 4294967.0
mTimeSTamp = 4294967054, mDoubleVal = 4294967.054, mFloatVal = 4294967.0
mTimeSTamp = 4294967056, mDoubleVal = 4294967.056, mFloatVal = 4294967.0
mTimeSTamp = 4294967058, mDoubleVal = 4294967.058, mFloatVal = 4294967.0

对比上面的mDoubleVal和mFloatVal,好像数据精度损失太大了。我需要精确到小数点后 3 位的浮点值。我怎样才能做到这一点?我知道由于表示形式的限制,我们不能准确地表示浮点数,但是看到这个限制从第一个小数点开始令人惊讶。

你不能。

A c/java/kotlin float 是 IEEE 单精度浮点数。因此,您将获得 24 位(23 位存储的尾数位,加上隐含的前导 1)或大约 7 位十进制数字的精度。当您在小数点前使用更多数字时,您在小数点后得到的数字就会减少。