Calculation of trigonometric sine function I'm creating a client-side pie chart in XSLT 1.0, without extensions or external dependencies (i.e., cannot use FXSLT, EXSLT, JavaScript, etc.).

The code is slow; at least fifteen iterations are necessary to get the correct precision required for the angles used by the pie chart. (I'm looking for help that doesn't involve loop unrolling, if possible.)

How would you speed calculating the sine function?

&lt;xsl:template name="power"&gt;
  &lt;xsl:param name="n"/&gt;
  &lt;xsl:param name="exponent"/&gt;
  &lt;xsl:param name="result" select="1" /&gt;
  &lt;xsl:choose&gt;
    &lt;xsl:when test="$exponent = 0"&gt;1&lt;/xsl:when&gt;
    &lt;xsl:when test="$exponent = 1"&gt;
      &lt;xsl:value-of select="$result * $n"/&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:otherwise&gt;
      &lt;xsl:call-template name="power"&gt;
        &lt;xsl:with-param name="n" select="$n"/&gt;
        &lt;xsl:with-param name="exponent" select="$exponent - 1"/&gt;
        &lt;xsl:with-param name="result" select="$result * $n"/&gt;
      &lt;/xsl:call-template&gt;                          
    &lt;/xsl:otherwise&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;

&lt;xsl:template name="factorial"&gt;
  &lt;xsl:param name="n" select="1" /&gt;

  &lt;xsl:choose&gt;
    &lt;xsl:when test="$n &amp;lt;= 1"&gt;1&lt;/xsl:when&gt;
    &lt;xsl:otherwise&gt;
      &lt;xsl:variable name="f"&gt;
        &lt;xsl:call-template name="factorial"&gt;
           &lt;xsl:with-param name="n" select="$n - 1" /&gt;
        &lt;/xsl:call-template&gt;
      &lt;/xsl:variable&gt;
      &lt;xsl:value-of select="$n * $f" /&gt;
    &lt;/xsl:otherwise&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;

&lt;!-- sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... --&gt;
&lt;xsl:template name="sin"&gt;
  &lt;xsl:param name="degrees" /&gt;
  &lt;xsl:param name="radians" select="$degrees * $PI div 180" /&gt;
  &lt;xsl:param name="iter" select="1" /&gt;
  &lt;xsl:param name="maxiter" select="15" /&gt;
  &lt;xsl:param name="result" select="0" /&gt;

  &lt;xsl:variable name="taylor" select="($iter - 1) * 2 + 1" /&gt;
  &lt;xsl:variable name="numerator"&gt;
    &lt;xsl:call-template name="power"&gt;
      &lt;xsl:with-param name="n" select="$radians" /&gt;
      &lt;xsl:with-param name="exponent" select="$taylor" /&gt;
    &lt;/xsl:call-template&gt;
  &lt;/xsl:variable&gt;
  &lt;xsl:variable name="denominator"&gt;
    &lt;xsl:call-template name="factorial"&gt;
      &lt;xsl:with-param name="n" select="$taylor" /&gt;
    &lt;/xsl:call-template&gt;
  &lt;/xsl:variable&gt;

  &lt;xsl:variable name="term"&gt;
    &lt;xsl:choose&gt;
      &lt;xsl:when test="$iter mod 2 = 1"&gt;
        &lt;xsl:value-of select="$numerator div $denominator" /&gt;
      &lt;/xsl:when&gt;
      &lt;xsl:otherwise&gt;&lt;xsl:value-of select="-1 * $numerator div $denominator" /&gt;&lt;/xsl:otherwise&gt;
    &lt;/xsl:choose&gt;
  &lt;/xsl:variable&gt;

  &lt;xsl:choose&gt;
    &lt;xsl:when test="$iter &amp;lt; $maxiter"&gt;
      &lt;xsl:call-template name="sin"&gt;
        &lt;xsl:with-param name="radians" select="$radians" /&gt;
        &lt;xsl:with-param name="iter" select="$iter + 1" /&gt;
        &lt;xsl:with-param name="result" select="$result + $term" /&gt;
      &lt;/xsl:call-template&gt;
    &lt;/xsl:when&gt;
    &lt;xsl:otherwise&gt;&lt;xsl:value-of select="$result" /&gt;&lt;/xsl:otherwise&gt;
  &lt;/xsl:choose&gt;
&lt;/xsl:template&gt;


A similar question exists for C, but loop unrolling is awkward in XSLT due to its immutable variables.
Do not use power and factorial. Notice that


  $$x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \ldots = x(1 - \frac{x^2}{2*3}(1 - \frac{x^2}{4*5}(1 - \frac{x^2}{6*7}(1 - \ldots))) \ldots) $$


Now calculate it backwards from the innermost term:

  &lt;!-- sin(x) = x(1 - (x^2/2*3)(1 - (x^2/4*5)(1 - (x^2/6*7)))) --&gt;
  &lt;xsl:template name="sin"&gt;
    &lt;xsl:param name="degrees" /&gt;
    &lt;xsl:param name="radians" select="$degrees * $PI div 180" /&gt;
    &lt;xsl:param name="iter" select="31" /&gt;
    &lt;xsl:param name="result" select="1" /&gt;

    &lt;xsl:variable name="term" select="($radians * $radians) div (($iter - 1) * $iter)" /&gt;

    &lt;xsl:choose&gt;
      &lt;xsl:when test="$iter &amp;gt; 2"&gt;
        &lt;xsl:call-template name="sin"&gt;
          &lt;xsl:with-param name="radians" select="$radians" /&gt;
          &lt;xsl:with-param name="iter" select="$iter - 2" /&gt;
          &lt;xsl:with-param name="result" select="1 - ($term * $result)" /&gt;
        &lt;/xsl:call-template&gt;
      &lt;/xsl:when&gt;
      &lt;xsl:otherwise&gt;&lt;xsl:value-of select="$radians * $result" /&gt;&lt;/xsl:otherwise&gt;
    &lt;/xsl:choose&gt;
  &lt;/xsl:template&gt;