我知道开始处理此问题的最简单方法是:
val floatNumber: Float = 123.456f
val decimalPart = floatNumber - floatNumber.toInt() //This would be 0.456 (I don't care about precision as this is not the main objective of my question)
现在在有笔和纸的现实世界中,如果我想将小数部分0.456“转换”为整数,我只需要乘以0.456 * 1000,就可以得到所需的结果,即456 (整数)。
许多提议的解决方案建议将数字拆分为字符串,然后以这种方式提取小数部分,但是我需要以数学方式获得解决方案,而不是使用字符串。
给出一个数字,使用未知的小数位数(转换为字符串并在。或之后计算字符是不可接受的),我需要仅使用数学将其小数部分“提取”为整数。
阅读这样的问题,没有运气:
How to get the decimal part of a float?
How to extract fractional digits of double/BigDecimal
如果有人知道Kotlin语言解决方案,那就太好了。我也将这个问题发布在数学平台上,以防万一。 How do I get whole and fractional parts from double in JSP/Java?
更新: 有没有一种“数学”方式来“计算”一个数字有多少个小数? (很明显,当您转换为字符串并计算字符数时,但是我需要避免使用字符串)这将是一个很重要的原因:十进制(0.456)* 10 *小数位数(3)将产生所需的结果。>
更新2 这不是我的用例,但我想它将澄清这个想法: 假设您要计算一个常量(例如PI),并希望返回一个整数,该整数最多为该常量小数部分的 50位数字。常量不必一定是无限的(例如可以为0.5,在这种情况下将返回“ 5”)
答案 0 :(得分:2)
我只需将小数乘以10(或将小数点移到右边),直到没有小数部分为止:
public static long fractionalDigitsLong(BigDecimal value) {
BigDecimal fractional = value.remainder(BigDecimal.ONE);
long digits;
do {
fractional = fractional.movePointRight(1); // or multiply(BigDecimal.TEN)
digits = fractional.longValue();
} while (fractional.compareTo(BigDecimal.valueOf(digits)) != 0);
return digits;
}
注意1:使用BigDecimal
可以避免浮点精度问题
注意2:使用compareTo
是因为equals
也会比较小数位数("0.0"
不等于"0.00"
)
(确保BigDecimal已经知道小数部分的大小,只知道scale()
返回的值)
补语:
如果使用BigDecimal
,则整个问题可以压缩为:
public static BigInteger fractionalDigits(BigDecimal value) {
return value.remainder(BigDecimal.ONE).stripTrailingZeros().unscaledValue();
}
如果需要,可以抑制剥离零点
答案 1 :(得分:1)
如果您将某些String转换器与method()配合使用,则不确定在此特定问题上是否对您不利。那是获得正确答案的一种方法。我知道您说过您不能使用String,但是可以在Custom方法中使用Strings吗?这样可以为您提供精确所需的答案。这是可以帮助我们转换数字的类:
class NumConvert{
String theNum;
public NumConvert(String theNum) {
this.theNum = theNum;
}
public int convert() {
String a = String.valueOf(theNum);
String[] b = a.split("\\.");
String b2 = b[1];
int zeros = b2.length();
String num = "1";
for(int x = 0; x < zeros; x++) {
num += "0";
}
float c = Float.parseFloat(theNum);
int multiply = Integer.parseInt(num);
float answer = c - (int)c;
int integerForm = (int)(answer * multiply);
return integerForm;
}
}
然后在您的主要班级:
public class ChapterOneBasics {
public static void main(String[] args) throws java.io.IOException{
NumConvert n = new NumConvert("123.456");
NumConvert q = new NumConvert("123.45600128");
System.out.println(q.convert());
System.out.println(n.convert());
}
}
输出:
45600128
456
答案 2 :(得分:1)
浮点数或双精度数不精确,仅是近似值-不精确。因此12.345在12.3449 ...和12.3450 ...之间。
这意味着不能将 12.340与12.34 区分开。 “小数部分”将是34除以100。 同样, 12.01的“小数部分” 1 除以100, 12.1的“小数部分”也将1 除以10。
因此,一个完整的算法将是(使用Java):
int[] decimalsAndDivider(double x) {
int decimalPart = 0;
int divider = 1;
final double EPS = 0.001;
for (;;) {
double error = x - (int)x;
if (-EPS < error && error < EPS) {
break;
}
x *= 10;
decimalPart = 10 * decimalPart + ((int)(x + EPS) % 10);
divider *= 10;
}
return new int[] { decimalPart, divider };
}
答案 3 :(得分:0)
我在测试了一段时间后于昨天发布了以下解决方案,后来发现由于浮动,双精度和十进制精度问题,该解决方案并不总是有效。
我的结论是,如果您想要无限的精度,这个问题是无法解决的:
因此,我将代码重新发布以供参考:
fun getDecimalCounter(d: Double): Int {
var temp = d
var tempInt = Math.floor(d)
var counter = 0
while ((temp - tempInt) > 0.0 ) {
temp *= 10
tempInt = Math.floor(temp)
counter++
}
return counter
}
fun main(args: Array <String> ) {
var d = 3.14159
if (d < 0) d = -d
val decimalCounter = getDecimalCounter(d)
val decimalPart = (d - Math.floor(d))
var decimalPartInt = Math.round(decimalPart * 10.0.pow(decimalCounter))
while (decimalPartInt % 10 == 0L) {
decimalPartInt /= 10
}
println(decimalPartInt)
}
由于精度较低,我掉落了浮子,并使用了双打。
由于精度的原因,最后的舍入也是必需的。