如何在java中将1200格式化为1.2k

如何在java中将1200格式化为1.2k,java,number-formatting,Java,Number Formatting,我想用java将以下数字格式化为它们旁边的数字: 1000 to 1k 5821 to 5.8k 10500 to 10k 101800 to 101k 2000000 to 2m 7800000 to 7.8m 92150000 to 92m 123200000 to 123m 右边的数字为长或整数,左边的数字为字符串。 我应该如何处理这个问题。我已经为此做了一点算法,但我认为可能已经有一些发明出来了,在这方面做得更好,如果我开始处理数十亿和万亿的数据,就不需要额外的测试:) 其他要求:

我想用java将以下数字格式化为它们旁边的数字:

1000 to 1k
5821 to 5.8k
10500 to 10k
101800 to 101k
2000000 to 2m
7800000 to 7.8m
92150000 to 92m
123200000 to 123m
右边的数字为长或整数,左边的数字为字符串。 我应该如何处理这个问题。我已经为此做了一点算法,但我认为可能已经有一些发明出来了,在这方面做得更好,如果我开始处理数十亿和万亿的数据,就不需要额外的测试:)

其他要求:

  • 格式最多应包含4个字符
  • 以上表示1.1k正常,11.2k不正常。7.8米也可以,19.1米不行。小数点前一位只能有小数点。小数点之前的两位数表示小数点之后的数字
  • 不需要四舍五入。(附加k和m的数字更多的是模拟仪表,表示近似值,而不是精确的逻辑条款。因此舍入是不相关的,这主要是因为变量的性质,即使在查看缓存结果时,舍入也可以增加或减少几个数字。)

    • 我的Java已经生锈了,但下面是我如何用C#实现它的:

      可以很容易地将其调整为使用CS千克(1024)而不是公制千克,或者添加更多单位。它将1000格式化为“1.0k”而不是“1k”,但我相信这并不重要

      为了满足更具体的要求“不超过四个字符”,请删除后缀前的空格,并按如下方式调整中间块:

      if (value >= unit)
        {
        value /= unit;
        return (value).ToString(value >= unit * 9.95 ? "#,##0" : "#,##0.0") + suffixes[--j];
        }
      

      我知道,这看起来更像一个C程序,但它是超轻量的

      public static void main(String args[]) {
          long[] numbers = new long[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
          for(long n : numbers) {
              System.out.println(n + " => " + coolFormat(n, 0));
          }
      }
      
      private static char[] c = new char[]{'k', 'm', 'b', 't'};
      
      /**
       * Recursive implementation, invokes itself for each factor of a thousand, increasing the class on each invokation.
       * @param n the number to format
       * @param iteration in fact this is the class from the array c
       * @return a String representing the number n formatted in a cool looking way.
       */
      private static String coolFormat(double n, int iteration) {
          double d = ((long) n / 100) / 10.0;
          boolean isRound = (d * 10) %10 == 0;//true if the decimal part is equal to 0 (then it's trimmed anyway)
          return (d < 1000? //this determines the class, i.e. 'k', 'm' etc
              ((d > 99.9 || isRound || (!isRound && d > 9.99)? //this decides whether to trim the decimals
               (int) d * 10 / 10 : d + "" // (int) d * 10 / 10 drops the decimal
               ) + "" + c[iteration]) 
              : coolFormat(d, iteration+1));
      
      }
      

      需要一些改进,但是:快来营救吧
      您可以将后缀放在字符串或数组中,然后根据幂或类似的值获取它们。
      部门也可以围绕权力进行管理,我认为几乎所有事情都与权力价值有关。 希望有帮助

      public static String formatValue(double value) {
      int power; 
          String suffix = " kmbt";
          String formattedNumber = "";
      
          NumberFormat formatter = new DecimalFormat("#,###.#");
          power = (int)StrictMath.log10(value);
          value = value/(Math.pow(10,(power/3)*3));
          formattedNumber=formatter.format(value);
          formattedNumber = formattedNumber + suffix.charAt(power/3);
          return formattedNumber.length()>4 ?  formattedNumber.replaceAll("\\.[0-9]+", "") : formattedNumber;  
      }
      
      产出:

      999
      1.2k
      98k
      911k
      1.1m
      11b
      712b
      34吨


      这里有一个利用DecimalFormat的工程符号的解决方案:

      public static void main(String args[]) {
          long[] numbers = new long[]{7, 12, 856, 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
          for(long number : numbers) {
              System.out.println(number + " = " + format(number));
          }
      }
      
      private static String[] suffix = new String[]{"","k", "m", "b", "t"};
      private static int MAX_LENGTH = 4;
      
      private static String format(double number) {
          String r = new DecimalFormat("##0E0").format(number);
          r = r.replaceAll("E[0-9]", suffix[Character.getNumericValue(r.charAt(r.length() - 1)) / 3]);
          while(r.length() > MAX_LENGTH || r.matches("[0-9]+\\.[a-z]")){
              r = r.substring(0, r.length()-2) + r.substring(r.length() - 1);
          }
          return r;
      }
      
      输出:

      7 = 7
      12 = 12
      856 = 856
      1000 = 1k
      5821 = 5.8k
      10500 = 10k
      101800 = 102k
      2000000 = 2m
      7800000 = 7.8m
      92150000 = 92m
      123200000 = 123m
      9999999 = 10m
      
      有一个基于规则的数字格式化程序,可用于数字拼写等。我认为使用ICU将为您提供一个可读和可维护的解决方案

      [用法]

      正确的类是RuleBasedNumber格式。格式本身可以存储为单独的文件(或字符串常量IIRC)

      来自


      同一页显示的是罗马数字,所以我想您的案例也应该是可能的。

      我的最爱。您也可以使用“k”等作为十进制的指示符,这在电子领域很常见。这将为您提供一个额外的数字,而不需要额外的空间

      第二列尝试使用尽可能多的数字

      1000 => 1.0k | 1000
      5821 => 5.8k | 5821
      10500 => 10k | 10k5
      101800 => 101k | 101k
      2000000 => 2.0m | 2m
      7800000 => 7.8m | 7m8
      92150000 => 92m | 92m1
      123200000 => 123m | 123m
      9999999 => 9.9m | 9m99
      
      这是密码

      public class HTTest {
      private static String[] unit = {"u", "k", "m", "g", "t"};
      /**
       * @param args
       */
      public static void main(String[] args) {
          int[] numbers = new int[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999};
          for(int n : numbers) {
              System.out.println(n + " => " + myFormat(n) + " | " + myFormat2(n));
          }
      }
      
      private static String myFormat(int pN) {
          String str = Integer.toString(pN);
          int len = str.length ()-1;
          if (len <= 3) return str;
          int level = len / 3;
          int mode = len % 3;
          switch (mode) {
          case 0: return str.substring(0, 1) + "." + str.substring(1, 2) + unit[level];
          case 1: return str.substring(0, 2) + unit[level];
          case 2: return str.substring(0, 3) + unit[level];
          }
          return "how that?";
      }
      private static String trim1 (String pVal) {
          if (pVal.equals("0")) return "";
          return pVal;
      }
      private static String trim2 (String pVal) {
          if (pVal.equals("00")) return "";
          return pVal.substring(0, 1) + trim1(pVal.substring(1,2));
      }
      private static String myFormat2(int pN) {
          String str = Integer.toString(pN);
          int len = str.length () - 1;
          if (len <= 3) return str;
          int level = len / 3;
          int mode = len % 3;
          switch (mode) {
          case 0: return str.substring(0, 1) + unit[level] + trim2(str.substring(1, 3));
          case 2: return str.substring(0, 3) + unit[level];
          case 1: return str.substring(0, 2) + unit[level] + trim1(str.substring(2, 3));
          }
          return "how that?";
      }
      }
      
      公共类测试{
      私有静态字符串[]单元={“u”、“k”、“m”、“g”、“t”};
      /**
      *@param args
      */
      公共静态void main(字符串[]args){
      int[]number=新的int[]{1000、5821、10500、101800、2000000、7800000、92150000、123200000、999999};
      用于(整数n:数字){
      System.out.println(n+“=>”+myFormat(n)+“|”+myFormat2(n));
      }
      }
      私有静态字符串myFormat(int-pN){
      字符串str=Integer.toString(pN);
      int len=str.length()-1;
      如果(len
      //代码更长,但工作正常。。。
      公共静态字符串格式(整数){
      如果(数字<999){
      返回字符串.valueOf(number);
      }
      如果(编号<9999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,1);
      字符串str2=strNumber.substring(1,2);
      如果(str2等于(“0”)){
      返回str1+“k”;
      }否则{
      返回str1+“+str2+”k”;
      }
      }
      如果(编号<99999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,2);
      返回str1+“k”;
      }
      如果(编号<999999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,3);
      返回str1+“k”;
      }
      如果(编号<9999999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,1);
      字符串str2=strNumber.substring(1,2);
      如果(str2等于(“0”)){
      返回str1+“m”;
      }否则{
      返回str1+“+str2+”m”;
      }
      }
      如果(编号<9999999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,2);
      返回str1+“m”;
      }
      如果(编号<9999999){
      String strNumber=String.valueOf(number);
      字符串str1=strNumber.substring(0,3);
      返回str1+“m”;
      }
      NumberFormat formatter hasdigi=新的十进制格式(“####,###,###,##”);
      返回格式hasdigi.format(数字);
      }
      
      我不知道这是否是最好的方法,但我就是这么做的

      7=>7
      12=>12
      856=>856
      1000=>1.0k
      5821=>5.82k
      10500=>10.5k
      101800=>101.8k
      2000000=>2.0m
      7800000=>7.8m
      92150000=>92.15m
      123200000=>123.2m
      9999999=>10.0m
      
      ---代码---

      当前答案的问题
      • 当前的许多解决方案都使用这些前缀k=103、m=106、b=109、t=1012。然而,根据本文,正确的前缀是k=103、m=106、G=109、t=1012
      • 缺乏对负数的支持(或至少缺乏证明负数得到支持的测试)
      • 缺乏对反向操作的支持,例如将1.1k转换为1100(尽管这超出了原始问题的范围)
      Java解决方案 此解决方案(的扩展)解决了上述问题

      import org.apache.commons.lang.math.NumberUtils;
      
      import java.text.DecimalFormat;
      import java.text.FieldPosition;
      import java.text.Format;
      import java.text.ParsePosition;
      import java.util.regex.Pattern;
      
      
      /**
       * Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
       * For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
       */
      class RoundedMetricPrefixFormat extends Format {
      
          private static final String[] METRIC_PREFIXES = new String[]{"", "k", "M", "G", "T"};
      
          /**
           * The maximum number of characters in the output, excluding the negative sign
           */
          private static final Integer MAX_LENGTH = 4;
      
          private static final Pattern TRAILING_DECIMAL_POINT = Pattern.compile("[0-9]+\\.[kMGT]");
      
          private static final Pattern METRIC_PREFIXED_NUMBER = Pattern.compile("\\-?[0-9]+(\\.[0-9])?[kMGT]");
      
          @Override
          public StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {
      
              Double number = Double.valueOf(obj.toString());
      
              // if the number is negative, convert it to a positive number and add the minus sign to the output at the end
              boolean isNegative = number < 0;
              number = Math.abs(number);
      
              String result = new DecimalFormat("##0E0").format(number);
      
              Integer index = Character.getNumericValue(result.charAt(result.length() - 1)) / 3;
              result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index]);
      
              while (result.length() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
                  int length = result.length();
                  result = result.substring(0, length - 2) + result.substring(length - 1);
              }
      
              return output.append(isNegative ? "-" + result : result);
          }
      
          /**
           * Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
           * the original number because <tt>format()</tt> is a lossy operation, e.g.
           *
           * <pre>
           * {@code
           * def formatter = new RoundedMetricPrefixFormat()
           * Long number = 5821L
           * String formattedNumber = formatter.format(number)
           * assert formattedNumber == '5.8k'
           *
           * Long parsedNumber = formatter.parseObject(formattedNumber)
           * assert parsedNumber == 5800
           * assert parsedNumber != number
           * }
           * </pre>
           *
           * @param source a number that may have a metric prefix
           * @param pos if parsing succeeds, this should be updated to the index after the last parsed character
           * @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
           */
          @Override
          public Object parseObject(String source, ParsePosition pos) {
      
              if (NumberUtils.isNumber(source)) {
      
                  // if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
                  pos.setIndex(source.length());
                  return toNumber(source);
      
              } else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {
      
                  boolean isNegative = source.charAt(0) == '-';
                  int length = source.length();
      
                  String number = isNegative ? source.substring(1, length - 1) : source.substring(0, length - 1);
                  String metricPrefix = Character.toString(source.charAt(length - 1));
      
                  Number absoluteNumber = toNumber(number);
      
                  int index = 0;
      
                  for (; index < METRIC_PREFIXES.length; index++) {
                      if (METRIC_PREFIXES[index].equals(metricPrefix)) {
                          break;
                      }
                  }
      
                  Integer exponent = 3 * index;
                  Double factor = Math.pow(10, exponent);
                  factor *= isNegative ? -1 : 1;
      
                  pos.setIndex(source.length());
                  Float result = absoluteNumber.floatValue() * factor.longValue();
                  return result.longValue();
              }
      
              return null;
          }
      
          private static Number toNumber(String number) {
              return NumberUtils.createNumber(number);
          }
      }
      

      添加我自己的答案、Java代码、自解释代码

      public static void main(String args[]) {
        long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};
        String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};
        for (int i = 0; i < numbers.length; i++) {
          long n = numbers[i];
          String formatted = format(n);
          System.out.println(n + " => " + formatted);
          if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);
        }
      }
      
      这里有一个解决方案,适用于任何长值,我发现它非常可读(核心逻辑在
      格式
      方法的底部三行中完成)

      它利用
      TreeMap
      找到合适的后缀。它比我以前编写的使用数组的解决方案效率更高,而且更难阅读

      System.out.println((long)(double)99999999999999992L); // 100000000000000000
      System.out.println((long)(double)99999999999999991L); //  99999999999999984
      // it is even worse for the logarithm:
      System.out.println(Math.log10(99999999999999600L)); // 17.0
      System.out.println(Math.log10(99999999999999500L)); // 16.999999999999996
      
      private static final NavigableMap后缀=newtreemap();
      静止的{
      
      7=>7
      12=>12
      856=>856
      1000=>1.0k
      5821=>5.82k
      10500=>10.5k
      101800=>101.8k
      2000000=>2.0m
      7800000=>7.8m
      92150000=>92.15m
      123200000=>123.2m
      9999999=>10.0m
      
      public String Format(Integer number){
          String[] suffix = new String[]{"k","m","b","t"};
          int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
          if (size >= 3){
              while (size % 3 != 0) {
                  size = size - 1;
              }
          }
          double notation = Math.pow(10, size);
          String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
          return result
      }
      
      import org.apache.commons.lang.math.NumberUtils;
      
      import java.text.DecimalFormat;
      import java.text.FieldPosition;
      import java.text.Format;
      import java.text.ParsePosition;
      import java.util.regex.Pattern;
      
      
      /**
       * Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
       * For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
       */
      class RoundedMetricPrefixFormat extends Format {
      
          private static final String[] METRIC_PREFIXES = new String[]{"", "k", "M", "G", "T"};
      
          /**
           * The maximum number of characters in the output, excluding the negative sign
           */
          private static final Integer MAX_LENGTH = 4;
      
          private static final Pattern TRAILING_DECIMAL_POINT = Pattern.compile("[0-9]+\\.[kMGT]");
      
          private static final Pattern METRIC_PREFIXED_NUMBER = Pattern.compile("\\-?[0-9]+(\\.[0-9])?[kMGT]");
      
          @Override
          public StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {
      
              Double number = Double.valueOf(obj.toString());
      
              // if the number is negative, convert it to a positive number and add the minus sign to the output at the end
              boolean isNegative = number < 0;
              number = Math.abs(number);
      
              String result = new DecimalFormat("##0E0").format(number);
      
              Integer index = Character.getNumericValue(result.charAt(result.length() - 1)) / 3;
              result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index]);
      
              while (result.length() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
                  int length = result.length();
                  result = result.substring(0, length - 2) + result.substring(length - 1);
              }
      
              return output.append(isNegative ? "-" + result : result);
          }
      
          /**
           * Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
           * the original number because <tt>format()</tt> is a lossy operation, e.g.
           *
           * <pre>
           * {@code
           * def formatter = new RoundedMetricPrefixFormat()
           * Long number = 5821L
           * String formattedNumber = formatter.format(number)
           * assert formattedNumber == '5.8k'
           *
           * Long parsedNumber = formatter.parseObject(formattedNumber)
           * assert parsedNumber == 5800
           * assert parsedNumber != number
           * }
           * </pre>
           *
           * @param source a number that may have a metric prefix
           * @param pos if parsing succeeds, this should be updated to the index after the last parsed character
           * @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
           */
          @Override
          public Object parseObject(String source, ParsePosition pos) {
      
              if (NumberUtils.isNumber(source)) {
      
                  // if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
                  pos.setIndex(source.length());
                  return toNumber(source);
      
              } else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {
      
                  boolean isNegative = source.charAt(0) == '-';
                  int length = source.length();
      
                  String number = isNegative ? source.substring(1, length - 1) : source.substring(0, length - 1);
                  String metricPrefix = Character.toString(source.charAt(length - 1));
      
                  Number absoluteNumber = toNumber(number);
      
                  int index = 0;
      
                  for (; index < METRIC_PREFIXES.length; index++) {
                      if (METRIC_PREFIXES[index].equals(metricPrefix)) {
                          break;
                      }
                  }
      
                  Integer exponent = 3 * index;
                  Double factor = Math.pow(10, exponent);
                  factor *= isNegative ? -1 : 1;
      
                  pos.setIndex(source.length());
                  Float result = absoluteNumber.floatValue() * factor.longValue();
                  return result.longValue();
              }
      
              return null;
          }
      
          private static Number toNumber(String number) {
              return NumberUtils.createNumber(number);
          }
      }
      
      import org.apache.commons.lang.math.NumberUtils
      
      import java.text.DecimalFormat
      import java.text.FieldPosition
      import java.text.Format
      import java.text.ParsePosition
      import java.util.regex.Pattern
      
      
      /**
       * Converts a number to a string in <a href="http://en.wikipedia.org/wiki/Metric_prefix">metric prefix</a> format.
       * For example, 7800000 will be formatted as '7.8M'. Numbers under 1000 will be unchanged. Refer to the tests for further examples.
       */
      class RoundedMetricPrefixFormat extends Format {
      
          private static final METRIC_PREFIXES = ["", "k", "M", "G", "T"]
      
          /**
           * The maximum number of characters in the output, excluding the negative sign
           */
          private static final Integer MAX_LENGTH = 4
      
          private static final Pattern TRAILING_DECIMAL_POINT = ~/[0-9]+\.[kMGT]/
      
          private static final Pattern METRIC_PREFIXED_NUMBER = ~/\-?[0-9]+(\.[0-9])?[kMGT]/
      
          @Override
          StringBuffer format(Object obj, StringBuffer output, FieldPosition pos) {
      
              Double number = obj as Double
      
              // if the number is negative, convert it to a positive number and add the minus sign to the output at the end
              boolean isNegative = number < 0
              number = Math.abs(number)
      
              String result = new DecimalFormat("##0E0").format(number)
      
              Integer index = Character.getNumericValue(result.charAt(result.size() - 1)) / 3
              result = result.replaceAll("E[0-9]", METRIC_PREFIXES[index])
      
              while (result.size() > MAX_LENGTH || TRAILING_DECIMAL_POINT.matcher(result).matches()) {
                  int length = result.size()
                  result = result.substring(0, length - 2) + result.substring(length - 1)
              }
      
              output << (isNegative ? "-$result" : result)
          }
      
          /**
           * Convert a String produced by <tt>format()</tt> back to a number. This will generally not restore
           * the original number because <tt>format()</tt> is a lossy operation, e.g.
           *
           * <pre>
           * {@code
           * def formatter = new RoundedMetricPrefixFormat()
           * Long number = 5821L
           * String formattedNumber = formatter.format(number)
           * assert formattedNumber == '5.8k'
           *
           * Long parsedNumber = formatter.parseObject(formattedNumber)
           * assert parsedNumber == 5800
           * assert parsedNumber != number
           * }
           * </pre>
           *
           * @param source a number that may have a metric prefix
           * @param pos if parsing succeeds, this should be updated to the index after the last parsed character
           * @return a Number if the the string is a number without a metric prefix, or a Long if it has a metric prefix
           */
          @Override
          Object parseObject(String source, ParsePosition pos) {
      
              if (source.isNumber()) {
      
                  // if the value is a number (without a prefix) don't return it as a Long or we'll lose any decimals
                  pos.index = source.size()
                  toNumber(source)
      
              } else if (METRIC_PREFIXED_NUMBER.matcher(source).matches()) {
      
                  boolean isNegative = source[0] == '-'
      
                  String number = isNegative ? source[1..-2] : source[0..-2]
                  String metricPrefix = source[-1]
      
                  Number absoluteNumber = toNumber(number)
      
                  Integer exponent = 3 * METRIC_PREFIXES.indexOf(metricPrefix)
                  Long factor = 10 ** exponent
                  factor *= isNegative ? -1 : 1
      
                  pos.index = source.size()
                  (absoluteNumber * factor) as Long
              }
          }
      
          private static Number toNumber(String number) {
              NumberUtils.createNumber(number)
          }
      }
      
      import java.text.Format
      import java.text.ParseException
      
      class RoundedMetricPrefixFormatTests extends GroovyTestCase {
      
          private Format roundedMetricPrefixFormat = new RoundedMetricPrefixFormat()
      
          void testNumberFormatting() {
      
              [
                      7L         : '7',
                      12L        : '12',
                      856L       : '856',
                      1000L      : '1k',
                      (-1000L)   : '-1k',
                      5821L      : '5.8k',
                      10500L     : '10k',
                      101800L    : '102k',
                      2000000L   : '2M',
                      7800000L   : '7.8M',
                      (-7800000L): '-7.8M',
                      92150000L  : '92M',
                      123200000L : '123M',
                      9999999L   : '10M',
                      (-9999999L): '-10M'
              ].each { Long rawValue, String expectedRoundValue ->
      
                  assertEquals expectedRoundValue, roundedMetricPrefixFormat.format(rawValue)
              }
          }
      
          void testStringParsingSuccess() {
              [
                      '7'    : 7,
                      '8.2'  : 8.2F,
                      '856'  : 856,
                      '-856' : -856,
                      '1k'   : 1000,
                      '5.8k' : 5800,
                      '-5.8k': -5800,
                      '10k'  : 10000,
                      '102k' : 102000,
                      '2M'   : 2000000,
                      '7.8M' : 7800000L,
                      '92M'  : 92000000L,
                      '-92M' : -92000000L,
                      '123M' : 123000000L,
                      '10M'  : 10000000L
      
              ].each { String metricPrefixNumber, Number expectedValue ->
      
                  def parsedNumber = roundedMetricPrefixFormat.parseObject(metricPrefixNumber)
                  assertEquals expectedValue, parsedNumber
              }
          }
      
          void testStringParsingFail() {
      
              shouldFail(ParseException) {
                  roundedMetricPrefixFormat.parseObject('notNumber')
              }
          }
      }
      
      import java.math.BigDecimal;
      
      /**
       * Method to convert number to formatted number.
       * 
       * @author Gautham PJ
       */
      public class ShortFormatNumbers
      {
      
          /**
           * Main method. Execution starts here.
           */
          public static void main(String[] args)
          {
      
              // The numbers that are being converted.
              int[] numbers = {999, 1400, 2500, 45673463, 983456, 234234567};
      
      
              // Call the "formatNumber" method on individual numbers to format 
              // the number.
              for(int number : numbers)
              {
                  System.out.println(number + ": " + formatNumber(number));
              }
      
          }
      
      
          /**
           * Format the number to display it in short format.
           * 
           * The number is divided by 1000 to find which denomination to be added 
           * to the number. Dividing the number will give the smallest possible 
           * value with the denomination.
           * 
           * @param the number that needs to be converted to short hand notation.
           * @return the converted short hand notation for the number.
           */
          private static String formatNumber(double number)
          {
              String[] denominations = {"", "k", "m", "b", "t"};
              int denominationIndex = 0;
      
              // If number is greater than 1000, divide the number by 1000 and 
              // increment the index for the denomination.
              while(number > 1000.0)
              {
                  denominationIndex++;
                  number = number / 1000.0;
              }
      
              // To round it to 2 digits.
              BigDecimal bigDecimal = new BigDecimal(number);
              bigDecimal = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_EVEN);
      
      
              // Add the number with the denomination to get the final value.
              String formattedNumber = bigDecimal + denominations[denominationIndex];
              return formattedNumber;
          }
      
      }
      
      private static final NavigableMap<Long, String> suffixes = new TreeMap<> ();
      static {
        suffixes.put(1_000L, "k");
        suffixes.put(1_000_000L, "M");
        suffixes.put(1_000_000_000L, "G");
        suffixes.put(1_000_000_000_000L, "T");
        suffixes.put(1_000_000_000_000_000L, "P");
        suffixes.put(1_000_000_000_000_000_000L, "E");
      }
      
      public static String format(long value) {
        //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
        if (value == Long.MIN_VALUE) return format(Long.MIN_VALUE + 1);
        if (value < 0) return "-" + format(-value);
        if (value < 1000) return Long.toString(value); //deal with easy case
      
        Entry<Long, String> e = suffixes.floorEntry(value);
        Long divideBy = e.getKey();
        String suffix = e.getValue();
      
        long truncated = value / (divideBy / 10); //the number part of the output times 10
        boolean hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
        return hasDecimal ? (truncated / 10d) + suffix : (truncated / 10) + suffix;
      }
      
      public static void main(String args[]) {
        long[] numbers = {0, 5, 999, 1_000, -5_821, 10_500, -101_800, 2_000_000, -7_800_000, 92_150_000, 123_200_000, 9_999_999, 999_999_999_999_999_999L, 1_230_000_000_000_000L, Long.MIN_VALUE, Long.MAX_VALUE};
        String[] expected = {"0", "5", "999", "1k", "-5.8k", "10k", "-101k", "2M", "-7.8M", "92M", "123M", "9.9M", "999P", "1.2P", "-9.2E", "9.2E"};
        for (int i = 0; i < numbers.length; i++) {
          long n = numbers[i];
          String formatted = format(n);
          System.out.println(n + " => " + formatted);
          if (!formatted.equals(expected[i])) throw new AssertionError("Expected: " + expected[i] + " but found: " + formatted);
        }
      }
      
      System.out.println((long)(double)99999999999999992L); // 100000000000000000
      System.out.println((long)(double)99999999999999991L); //  99999999999999984
      // it is even worse for the logarithm:
      System.out.println(Math.log10(99999999999999600L)); // 17.0
      System.out.println(Math.log10(99999999999999500L)); // 16.999999999999996
      
      private static final char[] magnitudes = {'k', 'M', 'G', 'T', 'P', 'E'}; // enough for long
      
      public static final String convert(long number) {
          String ret;
          if (number >= 0) {
              ret = "";
          } else if (number <= -9200000000000000000L) {
              return "-9.2E";
          } else {
              ret = "-";
              number = -number;
          }
          if (number < 1000)
              return ret + number;
          for (int i = 0; ; i++) {
              if (number < 10000 && number % 1000 >= 100)
                  return ret + (number / 1000) + '.' + ((number % 1000) / 100) + magnitudes[i];
              number /= 1000;
              if (number < 1000)
                  return ret + number + magnitudes[i];
          }
      }
      
      public class Test {
      
          public static void main(String[] args) {
              long[] numbers = new long[20000000];
              for (int i = 0; i < numbers.length; i++)
                  numbers[i] = Math.random() < 0.5 ? (long) (Math.random() * Long.MAX_VALUE) : (long) (Math.random() * Long.MIN_VALUE);
              System.out.println(convert1(numbers) + " vs. " + convert2(numbers));
          }
      
          private static long convert1(long[] numbers) {
              long l = System.currentTimeMillis();
              for (int i = 0; i < numbers.length; i++)
                  Converter1.convert(numbers[i]);
              return System.currentTimeMillis() - l;
          }
      
          private static long convert2(long[] numbers) {
              long l = System.currentTimeMillis();
              for (int i = 0; i < numbers.length; i++)
                  Converter2.coolFormat(numbers[i], 0);
              return System.currentTimeMillis() - l;
          }
      
      }
      
      import java.math.BigDecimal;
      
      public enum Threshold {
        TRILLION("1000000000000", 12, 't', null),
        BILLION("1000000000", 9, 'b', TRILLION),
        MILLION("1000000", 6, 'm', BILLION),
        THOUSAND("1000", 3, 'k', MILLION),
        ZERO("0", 0, null, THOUSAND);
      
        private BigDecimal value;
        private int zeroes;
        protected Character suffix;
        private Threshold higherThreshold;
      
        private Threshold(String aValueString, int aNumberOfZeroes, Character aSuffix,
            Threshold aThreshold) {
          value = new BigDecimal(aValueString);
          zeroes = aNumberOfZeroes;
          suffix = aSuffix;
          higherThreshold = aThreshold;
        }
      
        public static Threshold thresholdFor(long aValue) {
          return thresholdFor(new BigDecimal(aValue));
        }
      
        public static Threshold thresholdFor(BigDecimal aValue) {
          for (Threshold eachThreshold : Threshold.values()) {
            if (eachThreshold.value.compareTo(aValue) <= 0) {
              return eachThreshold;
            }
          }
          return TRILLION; // shouldn't be needed, but you might have to extend the enum
        }
      
        public int getNumberOfZeroes() {
          return zeroes;
        }
      
        public String getSuffix() {
          return suffix == null ? "" : "" + suffix;
        }
      
        public Threshold getHigherThreshold() {
          return higherThreshold;
        }
      }
      
      import java.math.BigDecimal;
      import java.math.RoundingMode;
      
      public class NumberShortener {
      
        public static final int REQUIRED_PRECISION = 2;
      
        public static BigDecimal toPrecisionWithoutLoss(BigDecimal aBigDecimal,
            int aPrecision, RoundingMode aMode) {
          int previousScale = aBigDecimal.scale();
          int previousPrecision = aBigDecimal.precision();
          int newPrecision = Math.max(previousPrecision - previousScale, aPrecision);
          return aBigDecimal.setScale(previousScale + newPrecision - previousPrecision,
              aMode);
        }
      
        private static BigDecimal scaledNumber(BigDecimal aNumber, RoundingMode aMode) {
          Threshold threshold = Threshold.thresholdFor(aNumber);
          BigDecimal adjustedNumber = aNumber.movePointLeft(threshold.getNumberOfZeroes());
          BigDecimal scaledNumber = toPrecisionWithoutLoss(adjustedNumber, REQUIRED_PRECISION,
              aMode).stripTrailingZeros();
          // System.out.println("Number: <" + aNumber + ">, adjusted: <" + adjustedNumber
          // + ">, rounded: <" + scaledNumber + ">");
          return scaledNumber;
        }
      
        public static String shortenedNumber(long aNumber, RoundingMode aMode) {
          boolean isNegative = aNumber < 0;
          BigDecimal numberAsBigDecimal = new BigDecimal(isNegative ? -aNumber : aNumber);
          Threshold threshold = Threshold.thresholdFor(numberAsBigDecimal);
          BigDecimal scaledNumber = aNumber == 0 ? numberAsBigDecimal : scaledNumber(
              numberAsBigDecimal, aMode);
          if (scaledNumber.compareTo(new BigDecimal("1000")) >= 0) {
            scaledNumber = scaledNumber(scaledNumber, aMode);
            threshold = threshold.getHigherThreshold();
          }
          String sign = isNegative ? "-" : "";
          String printNumber = sign + scaledNumber.stripTrailingZeros().toPlainString()
              + threshold.getSuffix();
          // System.out.println("Number: <" + sign + numberAsBigDecimal + ">, rounded: <"
          // + sign + scaledNumber + ">, print: <" + printNumber + ">");
          return printNumber;
        }
      }
      
      import static org.junit.Assert.*;
      
      import java.math.BigDecimal;
      import java.math.RoundingMode;
      
      import org.junit.Test;
      
      public class NumberShortenerTest {
      
        private static final long[] NUMBERS_FROM_OP = new long[] { 1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000 };
        private static final String[] EXPECTED_FROM_OP = new String[] { "1k", "5.8k", "10k", "101k", "2m", "7.8m", "92m", "123m" };
        private static final String[] EXPECTED_FROM_OP_HALF_UP = new String[] { "1k", "5.8k", "11k", "102k", "2m", "7.8m", "92m", "123m" };
        private static final long[] NUMBERS_TO_TEST = new long[] { 1, 500, 999, 1000, 1001, 1009, 1049, 1050, 1099, 1100, 12345, 123456, 999999, 1000000,
            1000099, 1000999, 1009999, 1099999, 1100000, 1234567, 999999999, 1000000000, 9123456789L, 123456789123L };
        private static final String[] EXPECTED_FROM_TEST = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1k", "1k", "1.1k", "12k", "123k",
            "999k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.2m", "999m", "1b", "9.1b", "123b" };
        private static final String[] EXPECTED_FROM_TEST_HALF_UP = new String[] { "1", "500", "999", "1k", "1k", "1k", "1k", "1.1k", "1.1k", "1.1k", "12k",
            "123k", "1m", "1m", "1m", "1m", "1m", "1.1m", "1.1m", "1.2m", "1b", "1b", "9.1b", "123b" };
      
        @Test
        public void testThresholdFor() {
          assertEquals(Threshold.ZERO, Threshold.thresholdFor(1));
          assertEquals(Threshold.ZERO, Threshold.thresholdFor(999));
          assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1000));
          assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(1234));
          assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(9999));
          assertEquals(Threshold.THOUSAND, Threshold.thresholdFor(999999));
          assertEquals(Threshold.MILLION, Threshold.thresholdFor(1000000));
        }
      
        @Test
        public void testToPrecision() {
          RoundingMode mode = RoundingMode.DOWN;
          assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
          assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
          assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
          assertEquals(new BigDecimal("1.234"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
          assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
              .toPlainString());
          assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
              .toPlainString());
          assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode).stripTrailingZeros()
              .toPlainString());
      
          mode = RoundingMode.HALF_UP;
          assertEquals(new BigDecimal("1"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 1, mode));
          assertEquals(new BigDecimal("1.2"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 2, mode));
          assertEquals(new BigDecimal("1.23"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 3, mode));
          assertEquals(new BigDecimal("1.235"), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("1.23456"), 4, mode));
          assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 4, mode).stripTrailingZeros()
              .toPlainString());
          assertEquals(new BigDecimal("999").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999"), 2, mode).stripTrailingZeros()
              .toPlainString());
          assertEquals(new BigDecimal("1000").toPlainString(), NumberShortener.toPrecisionWithoutLoss(new BigDecimal("999.9"), 2, mode)
              .stripTrailingZeros().toPlainString());
        }
      
        @Test
        public void testNumbersFromOP() {
          for (int i = 0; i < NUMBERS_FROM_OP.length; i++) {
            assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP[i],
                NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.DOWN));
            assertEquals("Index " + i + ": " + NUMBERS_FROM_OP[i], EXPECTED_FROM_OP_HALF_UP[i],
                NumberShortener.shortenedNumber(NUMBERS_FROM_OP[i], RoundingMode.HALF_UP));
          }
        }
      
        @Test
        public void testBorders() {
          assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.DOWN));
          assertEquals("Zero: " + 0, "0", NumberShortener.shortenedNumber(0, RoundingMode.HALF_UP));
          for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
            assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST[i],
                NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.DOWN));
            assertEquals("Index " + i + ": " + NUMBERS_TO_TEST[i], EXPECTED_FROM_TEST_HALF_UP[i],
                NumberShortener.shortenedNumber(NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
          }
        }
      
        @Test
        public void testNegativeBorders() {
          for (int i = 0; i < NUMBERS_TO_TEST.length; i++) {
            assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST[i],
                NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.DOWN));
            assertEquals("Index " + i + ": -" + NUMBERS_TO_TEST[i], "-" + EXPECTED_FROM_TEST_HALF_UP[i],
                NumberShortener.shortenedNumber(-NUMBERS_TO_TEST[i], RoundingMode.HALF_UP));
          }
        }
      }
      
      private static final char[] SUFFIXES = {'k', 'm', 'g', 't', 'p', 'e' };
      
      public static String format(long number) {
          if(number < 1000) {
              // No need to format this
              return String.valueOf(number);
          }
          // Convert to a string
          final String string = String.valueOf(number);
          // The suffix we're using, 1-based
          final int magnitude = (string.length() - 1) / 3;
          // The number of digits we must show before the prefix
          final int digits = (string.length() - 1) % 3 + 1;
      
          // Build the string
          char[] value = new char[4];
          for(int i = 0; i < digits; i++) {
              value[i] = string.charAt(i);
          }
          int valueLength = digits;
          // Can and should we add a decimal point and an additional number?
          if(digits == 1 && string.charAt(1) != '0') {
              value[valueLength++] = '.';
              value[valueLength++] = string.charAt(1);
          }
          value[valueLength++] = SUFFIXES[magnitude - 1];
          return new String(value, 0, valueLength);
      }
      
      static private String makeDecimal(long val, long div, String sfx) {
          val = val / (div / 10);
          long whole = val / 10;
          long tenths = val % 10;
          if ((tenths == 0) || (whole >= 10))
              return String.format("%d%s", whole, sfx);
          return String.format("%d.%d%s", whole, tenths, sfx);
      }
      
      static final long THOU =                1000L;
      static final long MILL =             1000000L;
      static final long BILL =          1000000000L;
      static final long TRIL =       1000000000000L;
      static final long QUAD =    1000000000000000L;
      static final long QUIN = 1000000000000000000L;
      
      static private String Xlat(long val) {
          if (val < THOU) return Long.toString(val);
          if (val < MILL) return makeDecimal(val, THOU, "k");
          if (val < BILL) return makeDecimal(val, MILL, "m");
          if (val < TRIL) return makeDecimal(val, BILL, "b");
          if (val < QUAD) return makeDecimal(val, TRIL, "t");
          if (val < QUIN) return makeDecimal(val, QUAD, "q");
          return makeDecimal(val, QUIN, "u");
      }
      
      public static void main(String[] args) {
          long vals[] = {
              999L, 1000L, 5821L, 10500L, 101800L, 2000000L,
              7800000L, 92150000L, 123200000L, 999999999L,
              1000000000L, 1100000000L, 999999999999L,
              1000000000000L, 999999999999999L,
              1000000000000000L, 9223372036854775807L
          };
          for (long val: vals)
              System.out.println ("" + val + " -> " + Xlat(val));
          }
      }
      
      999 -> 999
      1000 -> 1k
      5821 -> 5.8k
      10500 -> 10k
      101800 -> 101k
      2000000 -> 2m
      7800000 -> 7.8m
      92150000 -> 92m
      123200000 -> 123m
      999999999 -> 999m
      1000000000 -> 1b
      1100000000 -> 1.1b
      999999999999 -> 999b
      1000000000000 -> 1t
      999999999999999 -> 999t
      1000000000000000 -> 1q
      9223372036854775807 -> 9.2u
      
      private static char[] c = new char[]{'K', 'M', 'B', 'T'};
      private String formatK(double n, int iteration) {
          if (n < 1000) {
              // print 999 or 999K
              if (iteration <= 0) {
                  return String.valueOf((long) n);
              } else {
                  return String.format("%d%s", Math.round(n), c[iteration-1]);
              }
          } else if (n < 10000) {
              // Print 9.9K
              return String.format("%.1f%s", n/1000, c[iteration]);
          } else {
              // Increase 1 iteration
              return formatK(Math.round(n/1000), iteration+1);
          }
      }
      
       public static String formatNumberExample(Number number) {
              char[] suffix = {' ', 'k', 'M', 'B', 'T', 'P', 'E'};
              long numValue = number.longValue();
              int value = (int) Math.floor(Math.log10(numValue));
              int base = value / 3;
              if (value >= 3 && base < suffix.length) {
                  return new DecimalFormat("~#0.0").format(numValue / Math.pow(10, base * 3)) + suffix[base];
              } else {
                  return new DecimalFormat("#,##0").format(numValue);
              }
          }
      
      public String Format(Integer number){
          String[] suffix = new String[]{"k","m","b","t"};
          int size = (number.intValue() != 0) ? (int) Math.log10(number) : 0;
          if (size >= 3){
              while (size % 3 != 0) {
                  size = size - 1;
              }
          }
          double notation = Math.pow(10, size);
          String result = (size >= 3) ? + (Math.round((number / notation) * 100) / 100.0d)+suffix[(size/3) - 1] : + number + "";
          return result
      }
      
      public String formatValue(float value) {
          String arr[] = {"", "K", "M", "B", "T", "P", "E"};
          int index = 0;
          while ((value / 1000) >= 1) {
              value = value / 1000;
              index++;
          }
          DecimalFormat decimalFormat = new DecimalFormat("#.##");
          return String.format("%s %s", decimalFormat.format(value), arr[index]);
      }
      
      System.out.println(formatValue(100));     //  100
      System.out.println(formatValue(1000));    // 1 K
      System.out.println(formatValue(10345));   // 10.35 K
      System.out.println(formatValue(10012));   // 10.01 K
      System.out.println(formatValue(123456));  // 123.46 K
      System.out.println(formatValue(4384324)); // 4.38 M
      System.out.println(formatValue(10000000)); // 10 M
      System.out.println(formatValue(Long.MAX_VALUE)); // 9.22 E
      
      public static String getRoughNumber(long value) {
          if (value <= 999) {
              return String.valueOf(value);
          }
      
          final String[] units = new String[]{"", "K", "M", "B", "P"};
          int digitGroups = (int) (Math.log10(value) / Math.log10(1000));
          return new DecimalFormat("#,##0.#").format(value / Math.pow(1000, digitGroups)) + "" + units[digitGroups];
      
      }
      
      NumberFormat fmt = NumberFormat.getCompactNumberInstance(Locale.US, NumberFormat.Style.SHORT);
      
      fmt.format(1000)
      $5 ==> "1K"
      
      fmt.format(10000000)
      $9 ==> "10M"
      
      fmt.format(1000000000)
      $11 ==> "1B"
      
      public class NumberToReadableWordFormat {
      
          public static void main(String[] args) {
              Integer[] numbers = new Integer[]{1000, 5821, 10500, 101800, 2000000, 7800000, 92150000, 123200000, 9999999,999};
              for(int n : numbers) {
                  System.out.println(n + " => " + coolFormat(n));
              }
          }
      
          private static String[] c = new String[]{"K", "L", "Cr"};
          private static String coolFormat(int n) {
              int size = String.valueOf(n).length();
              if (size>=4 && size<6) {
                      int value = (int) Math.pow(10, 1);
                      double d = (double) Math.round(n/1000.0 * value) / value;
                      return (double) Math.round(n/1000.0 * value) / value+" "+c[0];
              } else if(size>5 && size<8) {
                      int value = (int) Math.pow(10, 1);
                      return (double) Math.round(n/100000.0 * value) / value+" "+c[1];
              } else if(size>=8) {
                      int value = (int) Math.pow(10, 1);
                      return (double) Math.round(n/10000000.0 * value) / value+" "+c[2];
              } else {
                  return n+"";
              }
          }
      }
      
      1000 => 1.0 K
      
      5821 => 5.8 K
      
      10500 => 10.5 K
      
      101800 => 1.0 L
      
      2000000 => 20.0 L
      
      7800000 => 78.0 L
      
      92150000 => 9.2 Cr
      
      123200000 => 12.3 Cr
      
      9999999 => 100.0 L
      
      999 => 999
      
      String abbr="M,K,T,B";
      
      public  String format(Double yvalue, String string,String abbr) {
          DecimalFormat df = new DecimalFormat(getnumberformatpattern(string));
            if (yvalue < 0) return "-" + format(-yvalue,string,abbr);
                double finalvalue= yvalue;
                String newnumber="";
                
                      if (abbr.indexOf("K")>0){   
                          finalvalue= (yvalue / 1e3);
                          newnumber=df.format(finalvalue) +'K';
                      }
                      if (abbr.indexOf("M")>0 ){
                      if(yvalue>=1e6){
                          finalvalue= (yvalue / 1e6);
                          newnumber=df.format(finalvalue) +'M';
                          };
                      }
                      if (abbr.indexOf("B")>0 )
                      {
                      if((newnumber.indexOf("M")<0) || yvalue>=1e9){
                          finalvalue= (yvalue / 1e9);
                          newnumber=df.format(finalvalue) +'B';                   }
                      }
                      if (abbr.indexOf("T")>0 ){ 
                      if((newnumber.indexOf("B")<0) || yvalue>=1e12){
                          finalvalue= (yvalue / 1e12);
                          newnumber=df.format(finalvalue) +'T';                   }
                      }
                      return newnumber;
          }
      
      <dependency>
        <groupId>com.github.bogdanovmn.humanreadablevalues</groupId>
        <artifactId>human-readable-values</artifactId>
        <version>1.0.1</version>
      </dependency>
      
      assertEquals(
          "2h 46m 40s",
          new SecondsValue(10000).fullString()
      );
      
      assertEquals(
          "2.8h",
          new SecondsValue(10000).shortString()
      );
      
      assertEquals(
          "9K 784b",
          new BytesValue(10000).fullString()
      );
      
      assertEquals(
          "9.8K",
          new BytesValue(10000).shortString()
      );