Java 为什么浮雕双掷不精确,浮雕双掷不精确?

Java 为什么浮雕双掷不精确,浮雕双掷不精确?,java,casting,floating-point,double,Java,Casting,Floating Point,Double,我知道浮点变量在转换时精度不高。但我不明白的是,为什么从较小的原语到较大原语的转换不精确,反之亦然。我可以理解,如果它是从双倍到浮动,但它是另一种方式。为什么会这样 请参见这两个测试的结果: @Test public void castTwoPrimitiveDecimalsUnpreciseToPrecise() { float var1 = 6.2f; double var2 = var1; assertThat(var2, is(6.2d)); //false,

我知道浮点变量在转换时精度不高。但我不明白的是,为什么从较小的原语到较大原语的转换不精确,反之亦然。我可以理解,如果它是从双倍到浮动,但它是另一种方式。为什么会这样

请参见这两个测试的结果:

@Test
public void castTwoPrimitiveDecimalsUnpreciseToPrecise()
{
    float var1 = 6.2f;
    double var2 = var1;

    assertThat(var2, is(6.2d)); //false, because it's 6.199999809265137
}

@Test
public void castTwoPrimitiviesDecimalsPreciseToUnpresice()
{
    double var1 = 7.6d;
    float var2 = (float)var1;

    assertThat(var2, is(7.6f)); //true
}

精度问题在于变量的初始化,而不是转换

在第一种情况下,从一个数字开始,该数字仅为十进制6.2的浮点近似值。转换为double将得到一个与浮点近似值完全相同的double。然后将其与更接近的双近似值进行比较,因此它当然不匹配


在第二种情况下,从十进制7.6的双重近似开始。然后将其转换为float。这将使双精度旋转为浮点数。两次四舍五入,在原始转换为双精度和转换为浮点时,可能会产生与直接将数字转换为浮点不同的答案,但通常会得到浮点近似值。然后将其与浮点近似值进行比较,因此得到匹配并不奇怪。

假设有人用尺子测量一个销钉,并确定其直径为3/8英寸。另一人用卡尺测量一个孔,发现其直径为9.5267mm。销钉是否适合该孔

如果将更粗糙的测量值转换为更高精度的形式,则会发现孔似乎比销钉大0.0017mm(即约1/15000”)。如果将它们都转换为较低精度的形式,就会发现这些值是无法区分的

如果测量为3/8”的peg实际上精确为9.525mm[精确的公制当量],则此类测量可以转换为更高的分辨率形式,而不会产生转换损失。但是,如果它只是表示“比23/64”或25/64更接近3/8”标记“,这种转换将导致一个通常被认为是近似值的值被解释为比实际值更精确

有些人会认为,事实上,桩和孔被视为不同的大小是一件好事。就我个人而言,我认为最好将它们视为无法区分。根据所描述的测量结果,没有特别的理由可以肯定地相信桩比孔大;这可能并不完全相等,但称它们不可区分比说挂钩更大更准确

就我个人而言,我讨厌那些只为了关闭编译器而要求将值写为或转换为[single precision]浮点值的语言规则。如果要将
浮点值设置为最接近4.7的值,可以简单地说:

float f=4.7;
并达到这一效果。看到以下情况的人:

static final float coef = 4.7f;
... some time later
float  f = coef;
double d = coef;
无法知道目标是将
d
设置为
double
值,该值等于最接近4.7的
float
值,还是将
d
设置为最接近4.7的
double
值。不幸的是,Java没有提供任何方法来声明一个常数,该常数可以在没有显式强制转换的情况下无声地分配给
float
,但当分配给
double
时,将使用该类型中可用的精度

顺便说一句,如果我的目标是将一些
double
变量
v
设置为最接近指定数值
coef
float
值,而不是最接近该数值的
double
值,我可能会非常明确地对其进行编码:

v = (double)(float)coef;

这将明确无误地表明一个事实,即程序员期望并打算为一个
双精度
分配一个先前四舍五入到
浮点
精度的值。如果没有<代码>(double)类型转换,就必须考虑程序员可能期望的可能性:代码> V<代码>为<代码>浮点(例如,当代码被写入时,它是<代码>浮点< /代码>,但从那时起它被更改为<代码> double < /代码>)。如果没有<代码>(浮标)<代码>类型转换,就必须考虑程序员预期“代码> COEF <代码> >为<代码>双< /代码>(例如,因为它已经被,但有人将它更改为浮标,以允许它分配给变量<代码>浮点< /代码>类型,而不需要编译器破解)。.

问题是,您使用的数字实际上都不是6.2或7.6…但有些数字与6.2和7.6相比,差异更大。