1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: ExsltMath.java,v 1.12 2004/02/11 17:56:36 minchau Exp $
  18. */
  19. package com.sun.org.apache.xalan.internal.lib;
  20. import com.sun.org.apache.xpath.internal.NodeSet;
  21. import org.w3c.dom.Node;
  22. import org.w3c.dom.NodeList;
  23. /**
  24. * This class contains EXSLT math extension functions.
  25. * It is accessed by specifying a namespace URI as follows:
  26. * <pre>
  27. * xmlns:math="http://exslt.org/math"
  28. * </pre>
  29. *
  30. * The documentation for each function has been copied from the relevant
  31. * EXSLT Implementer page.
  32. *
  33. * @see <a href="http://www.exslt.org/">EXSLT</a>
  34. * @xsl.usage general
  35. */
  36. public class ExsltMath extends ExsltBase
  37. {
  38. // Constants
  39. private static String PI = "3.1415926535897932384626433832795028841971693993751";
  40. private static String E = "2.71828182845904523536028747135266249775724709369996";
  41. private static String SQRRT2 = "1.41421356237309504880168872420969807856967187537694";
  42. private static String LN2 = "0.69314718055994530941723212145817656807550013436025";
  43. private static String LN10 = "2.302585092994046";
  44. private static String LOG2E = "1.4426950408889633";
  45. private static String SQRT1_2 = "0.7071067811865476";
  46. /**
  47. * The math:max function returns the maximum value of the nodes passed as the argument.
  48. * The maximum value is defined as follows. The node set passed as an argument is sorted
  49. * in descending order as it would be by xsl:sort with a data type of number. The maximum
  50. * is the result of converting the string value of the first node in this sorted list to
  51. * a number using the number function.
  52. * <p>
  53. * If the node set is empty, or if the result of converting the string values of any of the
  54. * nodes to a number is NaN, then NaN is returned.
  55. *
  56. * @param nl The NodeList for the node-set to be evaluated.
  57. *
  58. * @return the maximum value found, NaN if any node cannot be converted to a number.
  59. *
  60. * @see <a href="http://www.exslt.org/">EXSLT</a>
  61. */
  62. public static double max (NodeList nl)
  63. {
  64. if (nl == null || nl.getLength() == 0)
  65. return Double.NaN;
  66. double m = - Double.MAX_VALUE;
  67. for (int i = 0; i < nl.getLength(); i++)
  68. {
  69. Node n = nl.item(i);
  70. double d = toNumber(n);
  71. if (Double.isNaN(d))
  72. return Double.NaN;
  73. else if (d > m)
  74. m = d;
  75. }
  76. return m;
  77. }
  78. /**
  79. * The math:min function returns the minimum value of the nodes passed as the argument.
  80. * The minimum value is defined as follows. The node set passed as an argument is sorted
  81. * in ascending order as it would be by xsl:sort with a data type of number. The minimum
  82. * is the result of converting the string value of the first node in this sorted list to
  83. * a number using the number function.
  84. * <p>
  85. * If the node set is empty, or if the result of converting the string values of any of
  86. * the nodes to a number is NaN, then NaN is returned.
  87. *
  88. * @param nl The NodeList for the node-set to be evaluated.
  89. *
  90. * @return the minimum value found, NaN if any node cannot be converted to a number.
  91. *
  92. * @see <a href="http://www.exslt.org/">EXSLT</a>
  93. */
  94. public static double min (NodeList nl)
  95. {
  96. if (nl == null || nl.getLength() == 0)
  97. return Double.NaN;
  98. double m = Double.MAX_VALUE;
  99. for (int i = 0; i < nl.getLength(); i++)
  100. {
  101. Node n = nl.item(i);
  102. double d = toNumber(n);
  103. if (Double.isNaN(d))
  104. return Double.NaN;
  105. else if (d < m)
  106. m = d;
  107. }
  108. return m;
  109. }
  110. /**
  111. * The math:highest function returns the nodes in the node set whose value is the maximum
  112. * value for the node set. The maximum value for the node set is the same as the value as
  113. * calculated by math:max. A node has this maximum value if the result of converting its
  114. * string value to a number as if by the number function is equal to the maximum value,
  115. * where the equality comparison is defined as a numerical comparison using the = operator.
  116. * <p>
  117. * If any of the nodes in the node set has a non-numeric value, the math:max function will
  118. * return NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any
  119. * of the nodes in the node set has a non-numeric value, math:highest will return an empty
  120. * node set.
  121. *
  122. * @param nl The NodeList for the node-set to be evaluated.
  123. *
  124. * @return node-set with nodes containing the maximum value found, an empty node-set
  125. * if any node cannot be converted to a number.
  126. */
  127. public static NodeList highest (NodeList nl)
  128. {
  129. double maxValue = max(nl);
  130. NodeSet highNodes = new NodeSet();
  131. highNodes.setShouldCacheNodes(true);
  132. if (Double.isNaN(maxValue))
  133. return highNodes; // empty Nodeset
  134. for (int i = 0; i < nl.getLength(); i++)
  135. {
  136. Node n = nl.item(i);
  137. double d = toNumber(n);
  138. if (d == maxValue)
  139. highNodes.addElement(n);
  140. }
  141. return highNodes;
  142. }
  143. /**
  144. * The math:lowest function returns the nodes in the node set whose value is the minimum value
  145. * for the node set. The minimum value for the node set is the same as the value as calculated
  146. * by math:min. A node has this minimum value if the result of converting its string value to
  147. * a number as if by the number function is equal to the minimum value, where the equality
  148. * comparison is defined as a numerical comparison using the = operator.
  149. * <p>
  150. * If any of the nodes in the node set has a non-numeric value, the math:min function will return
  151. * NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any of the nodes
  152. * in the node set has a non-numeric value, math:lowest will return an empty node set.
  153. *
  154. * @param nl The NodeList for the node-set to be evaluated.
  155. *
  156. * @return node-set with nodes containing the minimum value found, an empty node-set
  157. * if any node cannot be converted to a number.
  158. *
  159. */
  160. public static NodeList lowest (NodeList nl)
  161. {
  162. double minValue = min(nl);
  163. NodeSet lowNodes = new NodeSet();
  164. lowNodes.setShouldCacheNodes(true);
  165. if (Double.isNaN(minValue))
  166. return lowNodes; // empty Nodeset
  167. for (int i = 0; i < nl.getLength(); i++)
  168. {
  169. Node n = nl.item(i);
  170. double d = toNumber(n);
  171. if (d == minValue)
  172. lowNodes.addElement(n);
  173. }
  174. return lowNodes;
  175. }
  176. /**
  177. * The math:abs function returns the absolute value of a number.
  178. *
  179. * @param num A number
  180. * @return The absolute value of the number
  181. */
  182. public static double abs(double num)
  183. {
  184. return Math.abs(num);
  185. }
  186. /**
  187. * The math:acos function returns the arccosine value of a number.
  188. *
  189. * @param num A number
  190. * @return The arccosine value of the number
  191. */
  192. public static double acos(double num)
  193. {
  194. return Math.acos(num);
  195. }
  196. /**
  197. * The math:asin function returns the arcsine value of a number.
  198. *
  199. * @param num A number
  200. * @return The arcsine value of the number
  201. */
  202. public static double asin(double num)
  203. {
  204. return Math.asin(num);
  205. }
  206. /**
  207. * The math:atan function returns the arctangent value of a number.
  208. *
  209. * @param num A number
  210. * @return The arctangent value of the number
  211. */
  212. public static double atan(double num)
  213. {
  214. return Math.atan(num);
  215. }
  216. /**
  217. * The math:atan2 function returns the angle ( in radians ) from the X axis to a point (y,x).
  218. *
  219. * @param num1 The X axis value
  220. * @param num2 The Y axis value
  221. * @return The angle (in radians) from the X axis to a point (y,x)
  222. */
  223. public static double atan2(double num1, double num2)
  224. {
  225. return Math.atan2(num1, num2);
  226. }
  227. /**
  228. * The math:cos function returns cosine of the passed argument.
  229. *
  230. * @param num A number
  231. * @return The cosine value of the number
  232. */
  233. public static double cos(double num)
  234. {
  235. return Math.cos(num);
  236. }
  237. /**
  238. * The math:exp function returns e (the base of natural logarithms) raised to a power.
  239. *
  240. * @param num A number
  241. * @return The value of e raised to the given power
  242. */
  243. public static double exp(double num)
  244. {
  245. return Math.exp(num);
  246. }
  247. /**
  248. * The math:log function returns the natural logarithm of a number.
  249. *
  250. * @param num A number
  251. * @return The natural logarithm of the number
  252. */
  253. public static double log(double num)
  254. {
  255. return Math.log(num);
  256. }
  257. /**
  258. * The math:power function returns the value of a base expression taken to a specified power.
  259. *
  260. * @param num1 The base
  261. * @param num2 The power
  262. * @return The value of the base expression taken to the specified power
  263. */
  264. public static double power(double num1, double num2)
  265. {
  266. return Math.pow(num1, num2);
  267. }
  268. /**
  269. * The math:random function returns a random number from 0 to 1.
  270. *
  271. * @return A random double from 0 to 1
  272. */
  273. public static double random()
  274. {
  275. return Math.random();
  276. }
  277. /**
  278. * The math:sin function returns the sine of the number.
  279. *
  280. * @param num A number
  281. * @return The sine value of the number
  282. */
  283. public static double sin(double num)
  284. {
  285. return Math.sin(num);
  286. }
  287. /**
  288. * The math:sqrt function returns the square root of a number.
  289. *
  290. * @param num A number
  291. * @return The square root of the number
  292. */
  293. public static double sqrt(double num)
  294. {
  295. return Math.sqrt(num);
  296. }
  297. /**
  298. * The math:tan function returns the tangent of the number passed as an argument.
  299. *
  300. * @param num A number
  301. * @return The tangent value of the number
  302. */
  303. public static double tan(double num)
  304. {
  305. return Math.tan(num);
  306. }
  307. /**
  308. * The math:constant function returns the specified constant to a set precision.
  309. * The possible constants are:
  310. * <pre>
  311. * PI
  312. * E
  313. * SQRRT2
  314. * LN2
  315. * LN10
  316. * LOG2E
  317. * SQRT1_2
  318. * </pre>
  319. * @param name The name of the constant
  320. * @param precision The precision
  321. * @return The value of the specified constant to the given precision
  322. */
  323. public static double constant(String name, double precision)
  324. {
  325. String value = null;
  326. if (name.equals("PI"))
  327. value = PI;
  328. else if (name.equals("E"))
  329. value = E;
  330. else if (name.equals("SQRRT2"))
  331. value = SQRRT2;
  332. else if (name.equals("LN2"))
  333. value = LN2;
  334. else if (name.equals("LN10"))
  335. value = LN10;
  336. else if (name.equals("LOG2E"))
  337. value = LOG2E;
  338. else if (name.equals("SQRT1_2"))
  339. value = SQRT1_2;
  340. if (value != null)
  341. {
  342. int bits = new Double(precision).intValue();
  343. if (bits <= value.length())
  344. value = value.substring(0, bits);
  345. return new Double(value).doubleValue();
  346. }
  347. else
  348. return Double.NaN;
  349. }
  350. }