为什么在 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 位十进制数字的精度。当您在小数点前使用更多数字时,您在小数点后得到的数字就会减少。
我正在使用 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 位十进制数字的精度。当您在小数点前使用更多数字时,您在小数点后得到的数字就会减少。