将double转换为十进制

3

我在将double转换为decimal时遇到了问题:

 public class CartesianCoordinates
    {
        public int LatitudeHours { get; set;}
        public int LatitudeMinutes { get; set; }
        public int LatitudeSeconds { get; set; }
        public GeoDirectionLongtitude LongitudeDirection { get; set; }

        public int LongitudeHours { get; set; }
        public int LongitudeMinutes { get; set; }
        public int LongitudeSeconds { get; set; }
        public GeoDirectionLatitude LatitudeDirection { get; set; }
    }

public class DecimalCoordinates
    {
        public decimal Latitude { get; set; }
        public decimal Longitude { get; set; }
    }

CartesianCoordinates CartesianCoordinates=new CartesianCoordinates(){LatitudeHours =12,LatitudeMinutes =34,LatitudeSeconds=56 }

     converterDecimalCoordinates.Latitude = CartesianCoordinates.LatitudeHours + (CartesianCoordinates.LatitudeMinutes + (CartesianCoordinates.LatitudeSeconds / 60)) / 60;

为什么我只得到了12?我想要的是12.55。
5个回答

9

您的所有计算都是整数计算,并且正在被舍入(更准确地说是截断)。尝试将60的字面值替换为60m以强制进行十进制计算,或者使用60.0以强制进行双精度浮点数计算(在这种情况下,您需要在最后转换为十进制)。


4
请注意,这里所谓的“取整”并不是四舍五入,而是向下取整。例如1.99在转换成整数时会变成1。 - Adam Houldsworth

7
Int32 x = 10;

Decimal y = x / 4;  // Performs an integer devision - result is 2.0
Decimal z = x / 4M; // Performs a decimal devision - result is 2.25

当两个操作数都是整数时,你会得到一个整数除法。通过在数字后添加后缀M,你可以明确地说明该数字应被解释为十进制数,因此你将得到一个十进制除法。


1
我经常遇到 Decimal x = 1M * [.. your calculation ..] 这种写法,这是一种快速简便的方法,可以通过将转换字面量放在前面来提高可读性和防止意外编辑导致的鲁棒性问题。 - Abel
@Abel - 不起作用,因为在这种情况下计算仍将作为整数除法执行。通过乘法进行后转换为十进制不会影响结果。 - David M
@David M:它确实有效。尝试这个语句,它将在x中产生2.5M:Decimal x = 1M * 5 / 2;(PS:我现在明白你的意思了:它取决于计算和执行顺序,也许并不总是一个好主意)。 - Abel
也许本不应该这样,但它确实有效。的确,这是执行顺序的问题。添加加法运算符就会失败。这只是运算符优先级的问题。吸取了教训 :) - Abel
正确。你和我的语句之间的区别在于括号。请查看我在这里的进一步阐述:https://dev59.com/qU_Sa4cB1Zd3GeqP8w5m#3245327 - Abel
显示剩余2条评论

3

作为我与David M和Daniel Brückner在这个答案下的讨论以及我在Adam的这个答案下部分错误的陈述的副产品,很遗憾地说,所有答案都只是部分正确的。发生的情况是这样的:

// example (all  x, y, z ar ints):
Decimal d = x + y + z / 60M;

// is left to right evaluated as
Decimal d = x + y + (((Decimal) z) / 60M);

// when doing addition, this is what happens when you add integers and something else:
Decimal d = x + y + (int) (((Decimal) z) / 60M);

// which will yield a truncated result.

结果是:仅仅在整个语句中添加60M60.0,正如建议的那样,可能不会产生所需的结果,这取决于语句的执行顺序和/或加减法的存在,就像OP问题中的情况一样。
要解决此问题,请遵循Adam的建议,将每个加/减步骤转换为小数,始终使用小数(不太清晰)或将计算放置在一个小函数中,该函数以小数作为参数,强制进行隐式转换。
Decimal GetDecimalLatitude(Decimal latitudeHours, Decimal latitudeMinutes, Decimal latitudeSeconds)
{
    return latitudeHours + (latitudeMinutes + (latitudeSeconds / 60)) / 60;
}

作为奖励,这样做更加简洁明了,有利于阅读。使用以下语句调用它:
converterDecimalCoordinates.Latitude = GetDecimalLatitude(
    CartesianCoordinates.LatitudeHours, 
    CartesianCoordinates.LatitudeMinutes,
    CartesianCoordinates.LatitudeSeconds);

3
您得到了12,因为在某些部分的计算中使用了int类型,因此无法保留精度-值被截断为一个int。我建议在计算之前将所有值转换为十进制数,或者像其他答案建议的那样,将字面量指定为十进制数。
更新:正如其他帖子所强调的那样,当前正在执行整数除法-我不知道这个技术术语,所以和您一样,今天我也学到了一些东西lol。

1
在计算中只需要一个小数点就可以将计算作为十进制进行。将所有的数字都转换成十进制有点麻烦。 - Abel
说实话,我并没有太关注计算本身的细节 - 但我确实理解由于整数除法引入了精度损失 - 其他答案已经澄清了这一点。此外,像这样的计算通常会在可读性方面有所提高,但代价是需要付出一些麻烦,我认为这是一个不错的权衡。我得不到爱 :-) - Adam Houldsworth
我错了,部分地,你确实得到了你应得的爱(和加分+1),我扩展了答案中的评论线程;-) - Abel

1

正如其他人已经提到的,你在除法运算的两侧都有一个整数。因此结果也是一个整数(然后将隐式转换为左侧的小数)。要解决这个问题,除法运算的一侧必须是小数,从而导致进行小数除法运算。因此,只需尝试使用以下代码行:

converterDecimalCoordinates.Latitude = CartesianCoordinates.LatitudeHours + (CartesianCoordinates.LatitudeMinutes + (CartesianCoordinates.LatitudeSeconds / 60)) / (decimal)60;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接