从Standard dictionary numbers开始,我需要一种最快的方法来转换下面的数字:
1000000 = 1百万
1435234 = 1.43百万
350000000 = 3.5亿
1000000000 = 10亿
1765000000 = 1.76亿
1000000000000 = 1万亿
1345342345000 = 1.34万亿
1000000000000000 = 1万亿
100000000000000000 = 100万亿
并且进一步。
我试过以下这样的话:
public String truncateNumber(float floatNumber) {
long million = 1000000L;
long billion = 1000000000L;
long trillion = 1000000000000L;
long number = Math.round(floatNumber);
if ((number >= million) && (number < billion)) {
float fraction = calculateFraction(number, million);
return Float.toString(fraction) + "M";
} else if ((number >= billion) && (number < trillion)) {
float fraction = calculateFraction(number, billion);
return Float.toString(fraction) + "B";
}
return Long.toString(number);
}
public float calculateFraction(long number, long divisor) {
long truncate = (number * 10L + (divisor / 2L)) / divisor;
float fraction = (float) truncate * 0.10F;
return fraction;
}
但我认为我的解决方案并不完全正确。那么,用Java做最快的方法是什么?非常感谢。
答案 0 :(得分:4)
第一个问题是float
没有足够的精度来表示这些数字。实际上,即使double
对于Nonillion范围内的值也没有足够的精度 - 尽管这在这里可能不那么重要,因为你显然想要丢弃这个数字的大部分信息。
尽管如此,我已使用BigInteger
在此处实现了它。如果您不关心精度问题,将其转换为使用double
应该是直截了当的。
这里的基本思想是从1000的幂到相应的数字名称创建NavigableMap
。可以使用floorEntry
快速查找此地图,以找到最佳匹配功率(因此,数字名称)。
import java.math.BigInteger;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.TreeMap;
public class NumberNames
{
public static void main(String[] args)
{
test("100", "Nearly nothing");
test("1000", "1 Thousand");
test("1230", "1.23 Thousand");
test("1000000", "1 Million");
test("1435234", "1.43 Million");
test("350000000", "350 Million");
test("1000000000", "1 Billion");
test("1765000000", "1.76 Billion");
test("1000000000000", "1 Trillion");
test("1345342345000", "1.34 Trillion");
test("1000000000000000", "1 Quadrillion");
test("100000000000000000", "100 Quadrillion");
test("1230000000000000000000000000000000000000000000000000000000000000", "1.23 Vigintillion");
}
private static void test(String numberString, String string)
{
BigInteger number = new BigInteger(numberString);
System.out.println(number+" is "+createString(number)+" should be "+string);
}
private static final String NAMES[] = new String[]{
"Thousand",
"Million",
"Billion",
"Trillion",
"Quadrillion",
"Quintillion",
"Sextillion",
"Septillion",
"Octillion",
"Nonillion",
"Decillion",
"Undecillion",
"Duodecillion",
"Tredecillion",
"Quattuordecillion",
"Quindecillion",
"Sexdecillion",
"Septendecillion",
"Octodecillion",
"Novemdecillion",
"Vigintillion",
};
private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
private static final NavigableMap<BigInteger, String> MAP;
static
{
MAP = new TreeMap<BigInteger, String>();
for (int i=0; i<NAMES.length; i++)
{
MAP.put(THOUSAND.pow(i+1), NAMES[i]);
}
}
public static String createString(BigInteger number)
{
Entry<BigInteger, String> entry = MAP.floorEntry(number);
if (entry == null)
{
return "Nearly nothing";
}
BigInteger key = entry.getKey();
BigInteger d = key.divide(THOUSAND);
BigInteger m = number.divide(d);
float f = m.floatValue() / 1000.0f;
float rounded = ((int)(f * 100.0))/100.0f;
if (rounded % 1 == 0)
{
return ((int)rounded) + " "+entry.getValue();
}
return rounded+" "+entry.getValue();
}
}
答案 1 :(得分:1)
我不会使用float
,因为它没有太多精确度。请改用double。
static final long MILLION = 1000000L;
static final long BILLION = 1000000000L;
static final long TRILLION = 1000000000000L;
public static String truncateNumber(double x) {
return x < MILLION ? String.valueOf(x) :
x < BILLION ? x / MILLION + "M" :
x < TRILLION ? x / BILLION + "B" :
x / TRILLION + "T";
}
答案 2 :(得分:1)
我个人用这个。如果输入数字中需要小数,则可以使用BigDecimal。
BigInteger / BigDecimal优于Float或Double或Long,因为它可以保持更大的值。
public static String customFormat(String pattern, BigInteger value) {
//To force the output to be equal if the language is set to english, spanish, norwegian or japanese.
NumberFormat nf = NumberFormat.getNumberInstance(Locale.ENGLISH);
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern(pattern);
String output = df.format(value);
return output;
}
public static String numberConverter(BigInteger input) {
String points = customFormat("###,###,###,###,###,###,###,###,###.###", input);
String[] letters = new String[]{"Kc","Mc","Gc","Tc","Pc","Ec","Zc","Yc","Bc"};//your value names. Is not limited to two letters. Can also be more based on your maximum amount
int size = points.length();
String after = points;
if (size > 3) {
int firstPoint = points.indexOf(".");
String re = points;
re = points.substring(0,3);
System.out.println(re);
int pVar = 7;
if(re.contains(",")){
String[] parts = re.split(",");
if(parts[0].length() == 2){
pVar = 6;
}else if(parts[0].length() == 1){
pVar = 5;
}
}
after = points.substring(0, pVar);
int x = (size - firstPoint - 4/*3*/)/5;
String bafter = after + " " + letters[x];//adds the value designation to the letter.
after = bafter;
}
return after;
}
我意识到由于它的长度,这不是最有效的代码,但它可以完美地运行。
1000以下的所有值都显示为其完整值。达到1000时,显示为1.000k。该代码旨在确保始终保持3个小数位。在if语句中将pvar设置向下更改为1(它始终将其设置为两位小数。)删除if语句将设置一个更大的动态数字,该数字会因max chars而变化。
有关BigINteger最大尺寸的一些技术信息。摘自this question:
“没有理论限制.BigInteger类为它所要求的所有数据位分配所需的内存。
然而,有一些实际限制,由可用内存决定。还有进一步的技术限制,虽然你不太可能受到影响:有些方法假设这些位可以被int索引寻址,所以当你超过Integer.MAX_VALUE
位时,事情就会开始中断。“
因此,如果您正在为计算机创建,请确保您有足够的内存用于那些大量的数据。
答案 3 :(得分:0)
简易Kotlin版本
const val MILLION = 1000000L
const val BILLION = 1000000000L
const val TRILLION = 1000000000000L
fun appendMillions(x: Long): String? {
return when {
x < MILLION -> x.toString()
x < BILLION -> "${x.times(100).div(MILLION).times(0.01)}M"
x < TRILLION -> "${x.times(100).div(BILLION).times(0.01)}B"
else -> "${x.times(100).div(TRILLION).times(0.01)}T"
}
}