You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SVFractionalFormat.java 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hssf.view;
  16. import java.text.*;
  17. /**
  18. * This class is used to format cells into their fractional format.
  19. *
  20. * I cant be 100% sure that the same fractional value will be displayed as in
  21. * excel but then again it is a lossy formating mode anyway
  22. *
  23. * @author Jason Height
  24. * @since 15 July 2002
  25. */
  26. public class SVFractionalFormat extends Format {
  27. private short ONE_DIGIT = 1;
  28. private short TWO_DIGIT = 2;
  29. private short THREE_DIGIT = 3;
  30. private short UNITS = 4;
  31. private int units = 1;
  32. private short mode = -1;
  33. /** Constructs a new FractionalFormatter
  34. *
  35. * The formatStr defines how the number will be formatted
  36. * # ?/? Up to one digit
  37. * # ??/?? Up to two digits
  38. * # ???/??? Up to three digits
  39. * # ?/2 In halves
  40. * # ?/4 In quarters
  41. * # ?/8 In eighths
  42. * # ?/16 In sixteenths
  43. * # ?/10 In tenths
  44. * # ?/100 In hundredths
  45. */
  46. public SVFractionalFormat(String formatStr) {
  47. if ("# ?/?".equals(formatStr))
  48. mode = ONE_DIGIT;
  49. else if ("# ??/??".equals(formatStr))
  50. mode = TWO_DIGIT;
  51. else if ("# ???/???".equals(formatStr))
  52. mode = THREE_DIGIT;
  53. else if ("# ?/2".equals(formatStr)) {
  54. mode = UNITS;
  55. units = 2;
  56. } else if ("# ?/4".equals(formatStr)) {
  57. mode = UNITS;
  58. units = 4;
  59. } else if ("# ?/8".equals(formatStr)) {
  60. mode = UNITS;
  61. units = 8;
  62. } else if ("# ?/16".equals(formatStr)) {
  63. mode = UNITS;
  64. units = 16;
  65. } else if ("# ?/10".equals(formatStr)) {
  66. mode = UNITS;
  67. units = 10;
  68. } else if ("# ?/100".equals(formatStr)) {
  69. mode = UNITS;
  70. units = 100;
  71. }
  72. }
  73. /**
  74. * Returns a fractional string representation of a double to a maximum denominator size
  75. *
  76. * This code has been translated to java from the following web page.
  77. * http://www.codeproject.com/cpp/fraction.asp
  78. * Originally coded in c++ By Dean Wyant dwyant@mindspring.com
  79. * The code on the web page is freely available.
  80. *
  81. * @param f Description of the Parameter
  82. * @param MaxDen Description of the Parameter
  83. * @return Description of the Return Value
  84. */
  85. private String format(final double f, final int MaxDen) {
  86. long Whole = (long)f;
  87. int sign = 1;
  88. if (f < 0) {
  89. sign = -1;
  90. }
  91. double Precision = 0.00001;
  92. double AllowedError = Precision;
  93. double d = Math.abs(f);
  94. d -= Whole;
  95. double Frac = d;
  96. double Diff = Frac;
  97. long Num = 1;
  98. long Den = 0;
  99. long A = 0;
  100. long B = 0;
  101. long i = 0;
  102. if (Frac > Precision) {
  103. while (true) {
  104. d = 1.0 / d;
  105. i = (long) (d + Precision);
  106. d -= i;
  107. if (A > 0) {
  108. Num = i * Num + B;
  109. }
  110. Den = (long) (Num / Frac + 0.5);
  111. Diff = Math.abs((double) Num / Den - Frac);
  112. if (Den > MaxDen) {
  113. if (A > 0) {
  114. Num = A;
  115. Den = (long) (Num / Frac + 0.5);
  116. Diff = Math.abs((double) Num / Den - Frac);
  117. } else {
  118. Den = MaxDen;
  119. Num = 1;
  120. Diff = Math.abs((double) Num / Den - Frac);
  121. if (Diff > Frac) {
  122. Num = 0;
  123. Den = 1;
  124. // Keeps final check below from adding 1 and keeps Den from being 0
  125. Diff = Frac;
  126. }
  127. }
  128. break;
  129. }
  130. if ((Diff <= AllowedError) || (d < Precision)) {
  131. break;
  132. }
  133. Precision = AllowedError / Diff;
  134. // This calcualtion of Precision does not always provide results within
  135. // Allowed Error. It compensates for loss of significant digits that occurs.
  136. // It helps to round the inprecise reciprocal values to i.
  137. B = A;
  138. A = Num;
  139. }
  140. }
  141. if (Num == Den) {
  142. Whole++;
  143. Num = 0;
  144. Den = 0;
  145. } else if (Den == 0) {
  146. Num = 0;
  147. }
  148. if (sign < 0) {
  149. if (Whole == 0) {
  150. Num = -Num;
  151. } else {
  152. Whole = -Whole;
  153. }
  154. }
  155. return new StringBuffer().append(Whole).append(" ").append(Num).append("/").append(Den).toString();
  156. }
  157. /** This method formats the double in the units specified.
  158. * The usints could be any number but in this current implementation it is
  159. * halves (2), quaters (4), eigths (8) etc
  160. */
  161. private String formatUnit(double f, int units) {
  162. long Whole = (long)f;
  163. f -= Whole;
  164. long Num = Math.round(f * units);
  165. return new StringBuffer().append(Whole).append(" ").append(Num).append("/").append(units).toString();
  166. }
  167. public final String format(double val) {
  168. if (mode == ONE_DIGIT) {
  169. return format(val, 9);
  170. } else if (mode == TWO_DIGIT) {
  171. return format(val, 99);
  172. } else if (mode == THREE_DIGIT) {
  173. return format(val, 999);
  174. } else if (mode == UNITS) {
  175. return formatUnit(val , units);
  176. }
  177. throw new RuntimeException("Unexpected Case");
  178. }
  179. public StringBuffer format(Object obj,
  180. StringBuffer toAppendTo,
  181. FieldPosition pos) {
  182. if (obj instanceof Number) {
  183. toAppendTo.append(format(((Number)obj).doubleValue()));
  184. return toAppendTo;
  185. }
  186. throw new IllegalArgumentException("Can only handle Numbers");
  187. }
  188. public Object parseObject(String source,
  189. ParsePosition status) {
  190. //JMH TBD
  191. return null;
  192. }
  193. public Object parseObject(String source)
  194. throws ParseException {
  195. //JMH TBD
  196. return null;
  197. }
  198. public Object clone() {
  199. //JMH TBD
  200. return null;
  201. }
  202. }