如何从大的小数中恢复初始分数
How to restore initial fraction from a big decimal
我有一个分数列表,必须先将其转换为 bigDecimal,然后再次转换为分数。我做了两种方法:首先从分数转换为 bigDecimal,第二种则相反。但是,我注意到在转换过程中我失去了一些精度,因此我想知道是否有办法以 100% 的信心将分数恢复到其初始状态,假设我可以存储任意数量的小数。
这是我的代码,在打印件上,您会注意到我在非常小的分数上失去了精度。
package Docs;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.math3.fraction.BigFraction;
public class FractionalApproximation{
private static BigDecimal fractionToPercentage(String fraction) {
final String[] split = fraction.split("/");
final float numerator = Float.valueOf(split[0]);
final float denominator = Float.valueOf(split[1]);
return new BigDecimal((numerator / denominator) * 100).setScale(3, BigDecimal.ROUND_HALF_DOWN);
}
private static String percentageToFraction(double share){
double percentage = share / 100;
BigFraction bigFraction = new BigFraction(percentage, 0.002D, 1000);
return bigFraction.getNumerator() + "/" + bigFraction.getDenominator();
}
public static void main(String[] args) {
List<String> initialFractions = new ArrayList<String>(Arrays.asList("1/3","1/112","1/6","1/1","1/56","1/224", "1/448", "4/448"));
System.out.println(initialFractions);
List<BigDecimal> percentageResultList = new ArrayList<BigDecimal>();
for(String fraction : initialFractions){
percentageResultList.add(fractionToPercentage(fraction));
}
System.out.println(percentageResultList);
List<String> fractionResultList = new ArrayList<String>();
for(BigDecimal value : percentageResultList){
fractionResultList.add(percentageToFraction(value.doubleValue()));
}
System.out.println(fractionResultList);
}
}
Initial fractions :[1/3, 1/112, 1/6, 1/1, 1/56, 1/224, 1/448, 4/448]
Fractions converted to BigDecimal: [33.333, 0.893, 16.667, 100.000, 1.786, 0.446, 0.223, 0.893]
BigDecimal converted to fraction: [1/3, 1/111, 1/6, 1/1, 1/55, 1/224, 1/448, 1/111]
我建议您研究连分数,尤其是阅读 https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations。该部分描述了如何使用计算连分数来更准确地表示给定的实数。
你还有两个问题需要处理。
一个是您将需要选择要继续多长时间,即您认为这些值中的哪些实际上贡献了应该表示的细节,而哪些只是来自计算的噪音。如果你的大小数没有数字噪音,即整数除法的直接和正确四舍五入的结果,那么你可以用相同的数字计算每个收敛的小数表示,看看它们中的哪一个与你的完全匹配输入。
另一个问题是,计算连分数需要进行大量运算,这些运算在使用大小数执行时会带来自身的舍入误差。特别是您将需要计算多个反转,即将 x 映射到 1/x。如果在第一步中将大小数转换为某种形式的大有理数(即两个大整数的商),然后在那里执行所有步骤,您可能会过得更好。初始转换和所有后续转换都应该在大有理表示中是准确的。
我有一个分数列表,必须先将其转换为 bigDecimal,然后再次转换为分数。我做了两种方法:首先从分数转换为 bigDecimal,第二种则相反。但是,我注意到在转换过程中我失去了一些精度,因此我想知道是否有办法以 100% 的信心将分数恢复到其初始状态,假设我可以存储任意数量的小数。
这是我的代码,在打印件上,您会注意到我在非常小的分数上失去了精度。
package Docs;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.math3.fraction.BigFraction;
public class FractionalApproximation{
private static BigDecimal fractionToPercentage(String fraction) {
final String[] split = fraction.split("/");
final float numerator = Float.valueOf(split[0]);
final float denominator = Float.valueOf(split[1]);
return new BigDecimal((numerator / denominator) * 100).setScale(3, BigDecimal.ROUND_HALF_DOWN);
}
private static String percentageToFraction(double share){
double percentage = share / 100;
BigFraction bigFraction = new BigFraction(percentage, 0.002D, 1000);
return bigFraction.getNumerator() + "/" + bigFraction.getDenominator();
}
public static void main(String[] args) {
List<String> initialFractions = new ArrayList<String>(Arrays.asList("1/3","1/112","1/6","1/1","1/56","1/224", "1/448", "4/448"));
System.out.println(initialFractions);
List<BigDecimal> percentageResultList = new ArrayList<BigDecimal>();
for(String fraction : initialFractions){
percentageResultList.add(fractionToPercentage(fraction));
}
System.out.println(percentageResultList);
List<String> fractionResultList = new ArrayList<String>();
for(BigDecimal value : percentageResultList){
fractionResultList.add(percentageToFraction(value.doubleValue()));
}
System.out.println(fractionResultList);
}
}
Initial fractions :[1/3, 1/112, 1/6, 1/1, 1/56, 1/224, 1/448, 4/448]
Fractions converted to BigDecimal: [33.333, 0.893, 16.667, 100.000, 1.786, 0.446, 0.223, 0.893]
BigDecimal converted to fraction: [1/3, 1/111, 1/6, 1/1, 1/55, 1/224, 1/448, 1/111]
我建议您研究连分数,尤其是阅读 https://en.wikipedia.org/wiki/Continued_fraction#Best_rational_approximations。该部分描述了如何使用计算连分数来更准确地表示给定的实数。
你还有两个问题需要处理。
一个是您将需要选择要继续多长时间,即您认为这些值中的哪些实际上贡献了应该表示的细节,而哪些只是来自计算的噪音。如果你的大小数没有数字噪音,即整数除法的直接和正确四舍五入的结果,那么你可以用相同的数字计算每个收敛的小数表示,看看它们中的哪一个与你的完全匹配输入。
另一个问题是,计算连分数需要进行大量运算,这些运算在使用大小数执行时会带来自身的舍入误差。特别是您将需要计算多个反转,即将 x 映射到 1/x。如果在第一步中将大小数转换为某种形式的大有理数(即两个大整数的商),然后在那里执行所有步骤,您可能会过得更好。初始转换和所有后续转换都应该在大有理表示中是准确的。