001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: ExsltMath.java 468639 2006-10-28 06:52:33Z minchau $
020 */
021 package org.apache.xalan.lib;
022
023 import org.apache.xpath.NodeSet;
024
025 import org.w3c.dom.Node;
026 import org.w3c.dom.NodeList;
027
028 /**
029 * This class contains EXSLT math extension functions.
030 * It is accessed by specifying a namespace URI as follows:
031 * <pre>
032 * xmlns:math="http://exslt.org/math"
033 * </pre>
034 *
035 * The documentation for each function has been copied from the relevant
036 * EXSLT Implementer page.
037 *
038 * @see <a href="http://www.exslt.org/">EXSLT</a>
039
040 * @xsl.usage general
041 */
042 public class ExsltMath extends ExsltBase
043 {
044 // Constants
045 private static String PI = "3.1415926535897932384626433832795028841971693993751";
046 private static String E = "2.71828182845904523536028747135266249775724709369996";
047 private static String SQRRT2 = "1.41421356237309504880168872420969807856967187537694";
048 private static String LN2 = "0.69314718055994530941723212145817656807550013436025";
049 private static String LN10 = "2.302585092994046";
050 private static String LOG2E = "1.4426950408889633";
051 private static String SQRT1_2 = "0.7071067811865476";
052
053 /**
054 * The math:max function returns the maximum value of the nodes passed as the argument.
055 * The maximum value is defined as follows. The node set passed as an argument is sorted
056 * in descending order as it would be by xsl:sort with a data type of number. The maximum
057 * is the result of converting the string value of the first node in this sorted list to
058 * a number using the number function.
059 * <p>
060 * If the node set is empty, or if the result of converting the string values of any of the
061 * nodes to a number is NaN, then NaN is returned.
062 *
063 * @param nl The NodeList for the node-set to be evaluated.
064 *
065 * @return the maximum value found, NaN if any node cannot be converted to a number.
066 *
067 * @see <a href="http://www.exslt.org/">EXSLT</a>
068 */
069 public static double max (NodeList nl)
070 {
071 if (nl == null || nl.getLength() == 0)
072 return Double.NaN;
073
074 double m = - Double.MAX_VALUE;
075 for (int i = 0; i < nl.getLength(); i++)
076 {
077 Node n = nl.item(i);
078 double d = toNumber(n);
079 if (Double.isNaN(d))
080 return Double.NaN;
081 else if (d > m)
082 m = d;
083 }
084
085 return m;
086 }
087
088 /**
089 * The math:min function returns the minimum value of the nodes passed as the argument.
090 * The minimum value is defined as follows. The node set passed as an argument is sorted
091 * in ascending order as it would be by xsl:sort with a data type of number. The minimum
092 * is the result of converting the string value of the first node in this sorted list to
093 * a number using the number function.
094 * <p>
095 * If the node set is empty, or if the result of converting the string values of any of
096 * the nodes to a number is NaN, then NaN is returned.
097 *
098 * @param nl The NodeList for the node-set to be evaluated.
099 *
100 * @return the minimum value found, NaN if any node cannot be converted to a number.
101 *
102 * @see <a href="http://www.exslt.org/">EXSLT</a>
103 */
104 public static double min (NodeList nl)
105 {
106 if (nl == null || nl.getLength() == 0)
107 return Double.NaN;
108
109 double m = Double.MAX_VALUE;
110 for (int i = 0; i < nl.getLength(); i++)
111 {
112 Node n = nl.item(i);
113 double d = toNumber(n);
114 if (Double.isNaN(d))
115 return Double.NaN;
116 else if (d < m)
117 m = d;
118 }
119
120 return m;
121 }
122
123 /**
124 * The math:highest function returns the nodes in the node set whose value is the maximum
125 * value for the node set. The maximum value for the node set is the same as the value as
126 * calculated by math:max. A node has this maximum value if the result of converting its
127 * string value to a number as if by the number function is equal to the maximum value,
128 * where the equality comparison is defined as a numerical comparison using the = operator.
129 * <p>
130 * If any of the nodes in the node set has a non-numeric value, the math:max function will
131 * return NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any
132 * of the nodes in the node set has a non-numeric value, math:highest will return an empty
133 * node set.
134 *
135 * @param nl The NodeList for the node-set to be evaluated.
136 *
137 * @return node-set with nodes containing the maximum value found, an empty node-set
138 * if any node cannot be converted to a number.
139 */
140 public static NodeList highest (NodeList nl)
141 {
142 double maxValue = max(nl);
143
144 NodeSet highNodes = new NodeSet();
145 highNodes.setShouldCacheNodes(true);
146
147 if (Double.isNaN(maxValue))
148 return highNodes; // empty Nodeset
149
150 for (int i = 0; i < nl.getLength(); i++)
151 {
152 Node n = nl.item(i);
153 double d = toNumber(n);
154 if (d == maxValue)
155 highNodes.addElement(n);
156 }
157 return highNodes;
158 }
159
160 /**
161 * The math:lowest function returns the nodes in the node set whose value is the minimum value
162 * for the node set. The minimum value for the node set is the same as the value as calculated
163 * by math:min. A node has this minimum value if the result of converting its string value to
164 * a number as if by the number function is equal to the minimum value, where the equality
165 * comparison is defined as a numerical comparison using the = operator.
166 * <p>
167 * If any of the nodes in the node set has a non-numeric value, the math:min function will return
168 * NaN. The definition numeric comparisons entails that NaN != NaN. Therefore if any of the nodes
169 * in the node set has a non-numeric value, math:lowest will return an empty node set.
170 *
171 * @param nl The NodeList for the node-set to be evaluated.
172 *
173 * @return node-set with nodes containing the minimum value found, an empty node-set
174 * if any node cannot be converted to a number.
175 *
176 */
177 public static NodeList lowest (NodeList nl)
178 {
179 double minValue = min(nl);
180
181 NodeSet lowNodes = new NodeSet();
182 lowNodes.setShouldCacheNodes(true);
183
184 if (Double.isNaN(minValue))
185 return lowNodes; // empty Nodeset
186
187 for (int i = 0; i < nl.getLength(); i++)
188 {
189 Node n = nl.item(i);
190 double d = toNumber(n);
191 if (d == minValue)
192 lowNodes.addElement(n);
193 }
194 return lowNodes;
195 }
196
197 /**
198 * The math:abs function returns the absolute value of a number.
199 *
200 * @param num A number
201 * @return The absolute value of the number
202 */
203 public static double abs(double num)
204 {
205 return Math.abs(num);
206 }
207
208 /**
209 * The math:acos function returns the arccosine value of a number.
210 *
211 * @param num A number
212 * @return The arccosine value of the number
213 */
214 public static double acos(double num)
215 {
216 return Math.acos(num);
217 }
218
219 /**
220 * The math:asin function returns the arcsine value of a number.
221 *
222 * @param num A number
223 * @return The arcsine value of the number
224 */
225 public static double asin(double num)
226 {
227 return Math.asin(num);
228 }
229
230 /**
231 * The math:atan function returns the arctangent value of a number.
232 *
233 * @param num A number
234 * @return The arctangent value of the number
235 */
236 public static double atan(double num)
237 {
238 return Math.atan(num);
239 }
240
241 /**
242 * The math:atan2 function returns the angle ( in radians ) from the X axis to a point (y,x).
243 *
244 * @param num1 The X axis value
245 * @param num2 The Y axis value
246 * @return The angle (in radians) from the X axis to a point (y,x)
247 */
248 public static double atan2(double num1, double num2)
249 {
250 return Math.atan2(num1, num2);
251 }
252
253 /**
254 * The math:cos function returns cosine of the passed argument.
255 *
256 * @param num A number
257 * @return The cosine value of the number
258 */
259 public static double cos(double num)
260 {
261 return Math.cos(num);
262 }
263
264 /**
265 * The math:exp function returns e (the base of natural logarithms) raised to a power.
266 *
267 * @param num A number
268 * @return The value of e raised to the given power
269 */
270 public static double exp(double num)
271 {
272 return Math.exp(num);
273 }
274
275 /**
276 * The math:log function returns the natural logarithm of a number.
277 *
278 * @param num A number
279 * @return The natural logarithm of the number
280 */
281 public static double log(double num)
282 {
283 return Math.log(num);
284 }
285
286 /**
287 * The math:power function returns the value of a base expression taken to a specified power.
288 *
289 * @param num1 The base
290 * @param num2 The power
291 * @return The value of the base expression taken to the specified power
292 */
293 public static double power(double num1, double num2)
294 {
295 return Math.pow(num1, num2);
296 }
297
298 /**
299 * The math:random function returns a random number from 0 to 1.
300 *
301 * @return A random double from 0 to 1
302 */
303 public static double random()
304 {
305 return Math.random();
306 }
307
308 /**
309 * The math:sin function returns the sine of the number.
310 *
311 * @param num A number
312 * @return The sine value of the number
313 */
314 public static double sin(double num)
315 {
316 return Math.sin(num);
317 }
318
319 /**
320 * The math:sqrt function returns the square root of a number.
321 *
322 * @param num A number
323 * @return The square root of the number
324 */
325 public static double sqrt(double num)
326 {
327 return Math.sqrt(num);
328 }
329
330 /**
331 * The math:tan function returns the tangent of the number passed as an argument.
332 *
333 * @param num A number
334 * @return The tangent value of the number
335 */
336 public static double tan(double num)
337 {
338 return Math.tan(num);
339 }
340
341 /**
342 * The math:constant function returns the specified constant to a set precision.
343 * The possible constants are:
344 * <pre>
345 * PI
346 * E
347 * SQRRT2
348 * LN2
349 * LN10
350 * LOG2E
351 * SQRT1_2
352 * </pre>
353 * @param name The name of the constant
354 * @param precision The precision
355 * @return The value of the specified constant to the given precision
356 */
357 public static double constant(String name, double precision)
358 {
359 String value = null;
360 if (name.equals("PI"))
361 value = PI;
362 else if (name.equals("E"))
363 value = E;
364 else if (name.equals("SQRRT2"))
365 value = SQRRT2;
366 else if (name.equals("LN2"))
367 value = LN2;
368 else if (name.equals("LN10"))
369 value = LN10;
370 else if (name.equals("LOG2E"))
371 value = LOG2E;
372 else if (name.equals("SQRT1_2"))
373 value = SQRT1_2;
374
375 if (value != null)
376 {
377 int bits = new Double(precision).intValue();
378
379 if (bits <= value.length())
380 value = value.substring(0, bits);
381
382 return new Double(value).doubleValue();
383 }
384 else
385 return Double.NaN;
386
387 }
388
389 }