1*b7275c88Smartynas /* $OpenBSD: epow.c,v 1.1 2011/07/02 18:11:01 martynas Exp $ */
2*b7275c88Smartynas
3*b7275c88Smartynas /*
4*b7275c88Smartynas * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net>
5*b7275c88Smartynas *
6*b7275c88Smartynas * Permission to use, copy, modify, and distribute this software for any
7*b7275c88Smartynas * purpose with or without fee is hereby granted, provided that the above
8*b7275c88Smartynas * copyright notice and this permission notice appear in all copies.
9*b7275c88Smartynas *
10*b7275c88Smartynas * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*b7275c88Smartynas * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*b7275c88Smartynas * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*b7275c88Smartynas * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*b7275c88Smartynas * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*b7275c88Smartynas * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*b7275c88Smartynas * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*b7275c88Smartynas */
18*b7275c88Smartynas
19*b7275c88Smartynas /* epow.c */
20*b7275c88Smartynas /* power function: z = x**y */
21*b7275c88Smartynas /* by Stephen L. Moshier. */
22*b7275c88Smartynas
23*b7275c88Smartynas
24*b7275c88Smartynas #include "ehead.h"
25*b7275c88Smartynas
26*b7275c88Smartynas extern int rndprc;
27*b7275c88Smartynas void epowi();
28*b7275c88Smartynas
epow(x,y,z)29*b7275c88Smartynas void epow( x, y, z )
30*b7275c88Smartynas unsigned short *x, *y, *z;
31*b7275c88Smartynas {
32*b7275c88Smartynas unsigned short w[NE];
33*b7275c88Smartynas int rndsav;
34*b7275c88Smartynas long li;
35*b7275c88Smartynas
36*b7275c88Smartynas efloor( y, w );
37*b7275c88Smartynas if( ecmp(y,w) == 0 )
38*b7275c88Smartynas {
39*b7275c88Smartynas eifrac( y, &li, w );
40*b7275c88Smartynas if( li < 0 )
41*b7275c88Smartynas li = -li;
42*b7275c88Smartynas if( (li < 0x7fffffff) && (li != 0x80000000) )
43*b7275c88Smartynas {
44*b7275c88Smartynas epowi( x, y, z );
45*b7275c88Smartynas return;
46*b7275c88Smartynas }
47*b7275c88Smartynas }
48*b7275c88Smartynas /* z = exp( y * log(x) ) */
49*b7275c88Smartynas rndsav = rndprc;
50*b7275c88Smartynas rndprc = NBITS;
51*b7275c88Smartynas elog( x, w );
52*b7275c88Smartynas emul( y, w, w );
53*b7275c88Smartynas eexp( w, z );
54*b7275c88Smartynas rndprc = rndsav;
55*b7275c88Smartynas emul( eone, z, z );
56*b7275c88Smartynas }
57*b7275c88Smartynas
58*b7275c88Smartynas
59*b7275c88Smartynas /* y is integer valued. */
60*b7275c88Smartynas
epowi(x,y,z)61*b7275c88Smartynas void epowi( x, y, z )
62*b7275c88Smartynas unsigned short x[], y[], z[];
63*b7275c88Smartynas {
64*b7275c88Smartynas unsigned short w[NE];
65*b7275c88Smartynas long li, lx;
66*b7275c88Smartynas unsigned long lu;
67*b7275c88Smartynas int rndsav;
68*b7275c88Smartynas unsigned short signx;
69*b7275c88Smartynas /* unsigned short signy; */
70*b7275c88Smartynas
71*b7275c88Smartynas rndsav = rndprc;
72*b7275c88Smartynas eifrac( y, &li, w );
73*b7275c88Smartynas if( li < 0 )
74*b7275c88Smartynas lx = -li;
75*b7275c88Smartynas else
76*b7275c88Smartynas lx = li;
77*b7275c88Smartynas
78*b7275c88Smartynas if( (lx == 0x7fffffff) || (lx == 0x80000000) )
79*b7275c88Smartynas {
80*b7275c88Smartynas epow( x, y, z );
81*b7275c88Smartynas goto done;
82*b7275c88Smartynas }
83*b7275c88Smartynas
84*b7275c88Smartynas if( (x[NE-1] & (unsigned short )0x7fff) == 0 )
85*b7275c88Smartynas {
86*b7275c88Smartynas if( li == 0 )
87*b7275c88Smartynas {
88*b7275c88Smartynas emov( eone, z );
89*b7275c88Smartynas return;
90*b7275c88Smartynas }
91*b7275c88Smartynas else if( li < 0 )
92*b7275c88Smartynas {
93*b7275c88Smartynas einfin( z );
94*b7275c88Smartynas return;
95*b7275c88Smartynas }
96*b7275c88Smartynas else
97*b7275c88Smartynas {
98*b7275c88Smartynas eclear( z );
99*b7275c88Smartynas return;
100*b7275c88Smartynas }
101*b7275c88Smartynas }
102*b7275c88Smartynas
103*b7275c88Smartynas if( li == 0L )
104*b7275c88Smartynas {
105*b7275c88Smartynas emov( eone, z );
106*b7275c88Smartynas return;
107*b7275c88Smartynas }
108*b7275c88Smartynas
109*b7275c88Smartynas emov( x, w );
110*b7275c88Smartynas signx = w[NE-1] & (unsigned short )0x8000;
111*b7275c88Smartynas w[NE-1] &= (unsigned short )0x7fff;
112*b7275c88Smartynas
113*b7275c88Smartynas /* Overflow detection */
114*b7275c88Smartynas /*
115*b7275c88Smartynas lx = li * (w[NE-1] - 0x3fff);
116*b7275c88Smartynas if( lx > 16385L )
117*b7275c88Smartynas {
118*b7275c88Smartynas einfin( z );
119*b7275c88Smartynas mtherr( "epowi", OVERFLOW );
120*b7275c88Smartynas goto done;
121*b7275c88Smartynas }
122*b7275c88Smartynas if( lx < -16450L )
123*b7275c88Smartynas {
124*b7275c88Smartynas eclear( z );
125*b7275c88Smartynas return;
126*b7275c88Smartynas }
127*b7275c88Smartynas */
128*b7275c88Smartynas rndprc = NBITS;
129*b7275c88Smartynas
130*b7275c88Smartynas if( li < 0 )
131*b7275c88Smartynas {
132*b7275c88Smartynas lu = (unsigned int )( -li );
133*b7275c88Smartynas /* signy = 0xffff;*/
134*b7275c88Smartynas ediv( w, eone, w );
135*b7275c88Smartynas }
136*b7275c88Smartynas else
137*b7275c88Smartynas {
138*b7275c88Smartynas lu = (unsigned int )li;
139*b7275c88Smartynas /* signy = 0;*/
140*b7275c88Smartynas }
141*b7275c88Smartynas
142*b7275c88Smartynas /* First bit of the power */
143*b7275c88Smartynas if( lu & 1 )
144*b7275c88Smartynas {
145*b7275c88Smartynas emov( w, z );
146*b7275c88Smartynas }
147*b7275c88Smartynas else
148*b7275c88Smartynas {
149*b7275c88Smartynas emov( eone, z );
150*b7275c88Smartynas signx = 0;
151*b7275c88Smartynas }
152*b7275c88Smartynas
153*b7275c88Smartynas
154*b7275c88Smartynas lu >>= 1;
155*b7275c88Smartynas while( lu != 0L )
156*b7275c88Smartynas {
157*b7275c88Smartynas emul( w, w, w ); /* arg to the 2-to-the-kth power */
158*b7275c88Smartynas if( lu & 1L ) /* if that bit is set, then include in product */
159*b7275c88Smartynas emul( w, z, z );
160*b7275c88Smartynas lu >>= 1;
161*b7275c88Smartynas }
162*b7275c88Smartynas
163*b7275c88Smartynas
164*b7275c88Smartynas done:
165*b7275c88Smartynas
166*b7275c88Smartynas if( signx )
167*b7275c88Smartynas eneg( z ); /* odd power of negative number */
168*b7275c88Smartynas
169*b7275c88Smartynas /*
170*b7275c88Smartynas if( signy )
171*b7275c88Smartynas {
172*b7275c88Smartynas if( ecmp( z, ezero ) != 0 )
173*b7275c88Smartynas {
174*b7275c88Smartynas ediv( z, eone, z );
175*b7275c88Smartynas }
176*b7275c88Smartynas else
177*b7275c88Smartynas {
178*b7275c88Smartynas einfin( z );
179*b7275c88Smartynas printf( "epowi OVERFLOW\n" );
180*b7275c88Smartynas }
181*b7275c88Smartynas }
182*b7275c88Smartynas */
183*b7275c88Smartynas rndprc = rndsav;
184*b7275c88Smartynas emul( eone, z, z );
185*b7275c88Smartynas }
186*b7275c88Smartynas
187*b7275c88Smartynas
188