File Coverage

NV.xs
Criterion Covered Total %
statement 130 190 68.4
branch 66 166 39.7
condition n/a
subroutine n/a
pod n/a
total 196 356 55.0


line stmt bran cond sub pod time code
1              
2             #ifdef __MINGW32__
3             #ifndef __USE_MINGW_ANSI_STDIO
4             #define __USE_MINGW_ANSI_STDIO 1
5             #endif
6             #endif
7              
8             #define PERL_NO_GET_CONTEXT 1
9              
10             #include "EXTERN.h"
11             #include "perl.h"
12             #include "XSUB.h"
13              
14             #ifdef NV_IS_FLOAT128
15             #include
16             #ifdef __MINGW64__
17             typedef __float128 float128 __attribute__ ((aligned(8)));
18             #else
19             typedef __float128 float128;
20             #endif
21             #endif
22             #include
23             #include
24              
25             #ifdef _MSC_VER
26             #ifndef strtold
27             #define strtold strtod
28             #endif
29             #endif
30              
31             #ifndef Newx
32             # define Newx(v,n,t) New(0,v,n,t)
33             #endif
34              
35             #ifdef NV_IS_FLOAT128
36             typedef float128 ARGTYPE;
37             #endif
38             #ifdef NV_IS_LONG_DOUBLE
39             typedef long double ARGTYPE;
40             #endif
41             #ifdef NV_IS_DOUBLE
42             typedef double ARGTYPE;
43             #endif
44              
45 4           SV * _itsa(pTHX_ SV * a) {
46 4 50         if(SvUOK(a)) return newSVuv(1);
47 4 50         if(SvIOK(a)) return newSVuv(2);
48 4 50         if(SvNOK(a)) return newSVuv(3);
49 4 50         if(SvPOK(a)) return newSVuv(4);
50 0           return newSVuv(0);
51             }
52              
53 4           void nv(pTHX_ SV * str) {
54 4           dXSARGS;
55             char * unparsed;
56             #ifdef NV_IS_FLOAT128
57             float128 num = strtoflt128(SvPV_nolen(str), &unparsed);
58             #endif
59             #ifdef NV_IS_LONG_DOUBLE
60             long double num = strtold(SvPV_nolen(str), &unparsed);
61             #endif
62             #ifdef NV_IS_DOUBLE
63 4 100         double num = strtod (SvPV_nolen(str), &unparsed);
64             #endif
65              
66 4 50         if(!SvIV(get_sv("Math::NV::no_warn", 0))) {
    100          
67 2 50         if(SvUV(_itsa(aTHX_ str)) != 4)
    50          
68 0           warn("Argument given to nv function is not a string - probably not what you want");
69             }
70              
71 4           ST(0) = sv_2mortal(newSVnv(num));
72 4 50         if(GIMME == G_ARRAY) {
    100          
73 1 50         EXTEND(SP, 1);
74 1 50         if(unparsed)
75 1           ST(1) = sv_2mortal(newSViv(strlen(unparsed)));
76             else
77 0           ST(1) = sv_2mortal(newSViv(0));
78 1           XSRETURN(2);
79             }
80 4           XSRETURN(1);
81             }
82              
83 2           SV * nv_type(pTHX) {
84             #ifdef NV_IS_FLOAT128
85             return newSVpv("__float128", 0);
86             #endif
87             #ifdef NV_IS_LONG_DOUBLE
88             return newSVpv("long double", 0);
89             #endif
90             #ifdef NV_IS_DOUBLE
91 2           return newSVpv("double", 0);
92             #endif
93             }
94              
95 1           unsigned long mant_dig(void) {
96             #ifdef NV_IS_FLOAT128
97             return FLT128_MANT_DIG;
98             #endif
99             #ifdef NV_IS_LONG_DOUBLE
100             return LDBL_MANT_DIG;
101             #endif
102             #ifdef NV_IS_DOUBLE
103 1           return DBL_MANT_DIG;
104             #endif
105             }
106              
107 4           int Isnan_ld (ARGTYPE d) {
108 4 50         if(d == d) return 0;
109 0           return 1;
110             }
111              
112             /********************************************************
113             Code for _ld2binary and _ld_str2binary plagiarised from
114             tests/tset_ld.c in the mpfr library source.
115             ********************************************************/
116              
117 1           void _ld2binary (pTHX_ SV * ld) {
118              
119 1           dXSARGS;
120 1 50         ARGTYPE d = (ARGTYPE)SvNV(ld);
121             ARGTYPE e;
122 1           int exp = 1;
123 1           unsigned long int prec = 0;
124 1           int returns = 0;
125              
126 1           sp = mark;
127              
128 1 50         if(Isnan_ld(d)) {
129 0 0         XPUSHs(sv_2mortal(newSVpv("@NaN@", 0)));
130 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
131 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
132 0           XSRETURN(3);
133             }
134              
135 1 50         if (d < (ARGTYPE) 0.0 || (d == (ARGTYPE) 0.0 && (1.0 / (double) d < 0.0))) {
    0          
    0          
136 1 50         XPUSHs(sv_2mortal(newSVpv("-", 0)));
137 1           returns++;
138 1           d = -d;
139             }
140              
141             /* now d >= 0 */
142             /* Use 2 differents tests for Inf, to avoid potential bugs
143             in implementations. */
144 1 50         if (Isnan_ld (d - d) || (d > 1 && d * 0.5 == d)) {
    50          
    50          
145 0 0         XPUSHs(sv_2mortal(newSVpv("@Inf@", 0)));
146 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
147 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
148 0           returns += 3;
149 0           XSRETURN(returns);
150             }
151              
152 1 50         if (d == (ARGTYPE) 0.0) {
153 0 0         XPUSHs(sv_2mortal(newSVpv("0.0", 0)));
154 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
155 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
156 0           returns += 3;
157 0           XSRETURN(returns);
158             }
159              
160             /* now d > 0 */
161 1           e = (ARGTYPE) 1.0;
162 1 50         while (e > d) {
163 0           e = e * (ARGTYPE) 0.5;
164 0           exp --;
165             }
166              
167             /* now d >= e */
168 10 100         while (d >= e + e) {
169 9           e = e + e;
170 9           exp ++;
171             }
172              
173             /* now e <= d < 2e */
174 1 50         XPUSHs(sv_2mortal(newSVpv("0.", 0)));
175 1           returns ++;
176              
177 13 100         while (d > (ARGTYPE) 0.0) {
178 12           prec++;
179 12 50         if(d >= e) {
180 12 50         XPUSHs(sv_2mortal(newSVpv("1", 0)));
181 12           returns ++;
182 12           d = (ARGTYPE) ((ARGTYPE) d - (ARGTYPE) e);
183             }
184             else {
185 0 0         XPUSHs(sv_2mortal(newSVpv("0", 0)));
186 0           returns ++;
187             }
188 12           e *= (ARGTYPE) 0.5;
189             }
190              
191 1 50         XPUSHs(sv_2mortal(newSViv(exp)));
192 1 50         XPUSHs(sv_2mortal(newSViv(prec)));
193 1           returns += 2;
194 1           XSRETURN(returns);
195             }
196              
197 1           void _ld_str2binary (pTHX_ char * ld) {
198              
199 1           dXSARGS;
200             ARGTYPE d;
201             ARGTYPE e;
202 1           int exp = 1;
203 1           unsigned long int prec = 0;
204 1           int returns = 0;
205              
206             #ifdef NV_IS_FLOAT128
207             d = strtoflt128(ld, NULL);
208             #endif
209             #ifdef NV_IS_LONG_DOUBLE
210             d = strtold(ld, NULL);
211             #endif
212             #ifdef NV_IS_DOUBLE
213 1           d = strtod(ld, NULL);
214             #endif
215              
216 1           sp = mark;
217              
218 1 50         if(Isnan_ld(d)) {
219 0 0         XPUSHs(sv_2mortal(newSVpv("@NaN@", 0)));
220 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
221 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
222 0           XSRETURN(3);
223             }
224              
225 1 50         if (d < (ARGTYPE) 0.0 || (d == (ARGTYPE) 0.0 && (1.0 / (double) d < 0.0))) {
    0          
    0          
226 1 50         XPUSHs(sv_2mortal(newSVpv("-", 0)));
227 1           returns++;
228 1           d = -d;
229             }
230              
231             /* now d >= 0 */
232             /* Use 2 differents tests for Inf, to avoid potential bugs
233             in implementations. */
234 1 50         if (Isnan_ld (d - d) || (d > 1 && d * 0.5 == d)) {
    50          
    50          
235 0 0         XPUSHs(sv_2mortal(newSVpv("@Inf@", 0)));
236 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
237 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
238 0           returns += 3;
239 0           XSRETURN(returns);
240             }
241              
242 1 50         if (d == (ARGTYPE) 0.0) {
243 0 0         XPUSHs(sv_2mortal(newSVpv("0.0", 0)));
244 0 0         XPUSHs(sv_2mortal(newSViv(exp)));
245 0 0         XPUSHs(sv_2mortal(newSViv(prec)));
246 0           returns += 3;
247 0           XSRETURN(returns);
248             }
249              
250             /* now d > 0 */
251 1           e = (ARGTYPE) 1.0;
252 1 50         while (e > d) {
253 0           e = e * (ARGTYPE) 0.5;
254 0           exp --;
255             }
256              
257             /* now d >= e */
258 10 100         while (d >= e + e) {
259 9           e = e + e;
260 9           exp ++;
261             }
262              
263             /* now e <= d < 2e */
264 1 50         XPUSHs(sv_2mortal(newSVpv("0.", 0)));
265 1           returns ++;
266              
267 13 100         while (d > (ARGTYPE) 0.0) {
268 12           prec++;
269 12 50         if(d >= e) {
270 12 50         XPUSHs(sv_2mortal(newSVpv("1", 0)));
271 12           returns ++;
272 12           d = (ARGTYPE) ((ARGTYPE) d - (ARGTYPE) e);
273             }
274             else {
275 0 0         XPUSHs(sv_2mortal(newSVpv("0", 0)));
276 0           returns ++;
277             }
278 12           e *= (ARGTYPE) 0.5;
279             }
280              
281 1 50         XPUSHs(sv_2mortal(newSViv(exp)));
282 1 50         XPUSHs(sv_2mortal(newSViv(prec)));
283 1           returns += 2;
284 1           XSRETURN(returns);
285             }
286              
287 1           SV * _bin2val(pTHX_ SV * precision, SV * exponent, SV * bin) {
288             IV i, prec;
289 1 50         prec = SvIV(precision);
290              
291 1           ARGTYPE d = (ARGTYPE)0.0;
292 1 50         ARGTYPE exp = (ARGTYPE)SvNV(exponent);
293 13 100         for(i = 0; i < prec; i++) {
294 12 50         if(SvIV(*(av_fetch((AV*)SvRV(bin), i, 0))))
    50          
295             #ifdef NV_IS_FLOAT128
296             d += powq(2.0Q, exp);
297             #endif
298             #ifdef NV_IS_LONG_DOUBLE
299             d += powl(2.0L, exp);
300             #endif
301             #ifdef NV_IS_DOUBLE
302 12           d += pow(2.0, exp);
303             #endif
304 12           exp -= (ARGTYPE)1.0;
305             }
306              
307 1           return newSVnv(d);
308             }
309              
310 0           SV * _bug_95e20(pTHX) {
311             #ifdef NV_IS_FLOAT128
312             return newSVnv(95e20Q);
313             #endif
314             #ifdef NV_IS_LONG_DOUBLE
315             return newSVnv(95e20L);
316             #endif
317             #ifdef NV_IS_DOUBLE
318 0           return newSVnv(95e20);
319             #endif
320             }
321              
322 0           SV * _bug_1175557635e10(pTHX) {
323             #ifdef NV_IS_FLOAT128
324             return newSVnv(1175557635e10Q);
325             #endif
326             #ifdef NV_IS_LONG_DOUBLE
327             return newSVnv(1175557635e10L);
328             #endif
329             #ifdef NV_IS_DOUBLE
330 0           return newSVnv(1175557635e10);
331             #endif
332             }
333              
334 1           void Cprintf(pTHX_ char * fmt, SV * nv) {
335 1 50         printf(fmt, (ARGTYPE)SvNV(nv));
336 1           }
337              
338 1           void Csprintf(pTHX_ char * fmt, SV * nv, int size) {
339 1           dXSARGS;
340             char * out;
341              
342 1           Newx(out, size, char);
343 1 50         if(out == NULL) croak("Failed to allocate memory in Csprintf function");
344             #ifdef NV_IS_FLOAT128
345             quadmath_snprintf(out, size, fmt, (__float128)SvNV(nv));
346             #else
347 1 50         sprintf(out, fmt, (ARGTYPE)SvNV(nv));
348             #endif
349              
350 1           ST(0) = sv_2mortal(newSVpv(out, 0));
351 1           Safefree(out);
352 1           XSRETURN(1);
353              
354             }
355              
356             /* Provide our own looks_like_number() for use by test suite. */
357              
358 0           int _looks_like_number(pTHX_ SV * x) {
359              
360 0 0         if(looks_like_number(x)) return 1;
361 0           return 0;
362              
363             }
364              
365              
366              
367              
368             MODULE = Math::NV PACKAGE = Math::NV
369              
370             PROTOTYPES: DISABLE
371              
372              
373             SV *
374             _itsa (a)
375             SV * a
376             CODE:
377 0           RETVAL = _itsa (aTHX_ a);
378             OUTPUT: RETVAL
379              
380             void
381             nv (str)
382             SV * str
383             PREINIT:
384             I32* temp;
385             PPCODE:
386 4           temp = PL_markstack_ptr++;
387 4           nv(aTHX_ str);
388 4 50         if (PL_markstack_ptr != temp) {
389             /* truly void, because dXSARGS not invoked */
390 0           PL_markstack_ptr = temp;
391 0           XSRETURN_EMPTY; /* return empty stack */
392             }
393             /* must have used dXSARGS; list context implied */
394 4           return; /* assume stack size is correct */
395              
396             SV *
397             nv_type ()
398             CODE:
399 2           RETVAL = nv_type (aTHX);
400             OUTPUT: RETVAL
401              
402              
403             unsigned long
404             mant_dig ()
405              
406              
407             void
408             _ld2binary (ld)
409             SV * ld
410             PREINIT:
411             I32* temp;
412             PPCODE:
413 1           temp = PL_markstack_ptr++;
414 1           _ld2binary(aTHX_ ld);
415 1 50         if (PL_markstack_ptr != temp) {
416             /* truly void, because dXSARGS not invoked */
417 0           PL_markstack_ptr = temp;
418 0           XSRETURN_EMPTY; /* return empty stack */
419             }
420             /* must have used dXSARGS; list context implied */
421 1           return; /* assume stack size is correct */
422              
423             void
424             _ld_str2binary (ld)
425             char * ld
426             PREINIT:
427             I32* temp;
428             PPCODE:
429 1           temp = PL_markstack_ptr++;
430 1           _ld_str2binary(aTHX_ ld);
431 1 50         if (PL_markstack_ptr != temp) {
432             /* truly void, because dXSARGS not invoked */
433 0           PL_markstack_ptr = temp;
434 0           XSRETURN_EMPTY; /* return empty stack */
435             }
436             /* must have used dXSARGS; list context implied */
437 1           return; /* assume stack size is correct */
438              
439             SV *
440             _bin2val (precision, exponent, bin)
441             SV * precision
442             SV * exponent
443             SV * bin
444             CODE:
445 1           RETVAL = _bin2val (aTHX_ precision, exponent, bin);
446             OUTPUT: RETVAL
447              
448             SV *
449             _bug_95e20 ()
450             CODE:
451 0           RETVAL = _bug_95e20 (aTHX);
452             OUTPUT: RETVAL
453              
454              
455             SV *
456             _bug_1175557635e10 ()
457             CODE:
458 0           RETVAL = _bug_1175557635e10 (aTHX);
459             OUTPUT: RETVAL
460              
461              
462             void
463             Cprintf (fmt, nv)
464             char * fmt
465             SV * nv
466             PREINIT:
467             I32* temp;
468             PPCODE:
469 1           temp = PL_markstack_ptr++;
470 1           Cprintf(aTHX_ fmt, nv);
471 1 50         if (PL_markstack_ptr != temp) {
472             /* truly void, because dXSARGS not invoked */
473 1           PL_markstack_ptr = temp;
474 1           XSRETURN_EMPTY; /* return empty stack */
475             }
476             /* must have used dXSARGS; list context implied */
477 0           return; /* assume stack size is correct */
478              
479             void
480             Csprintf (fmt, nv, size)
481             char * fmt
482             SV * nv
483             int size
484             PREINIT:
485             I32* temp;
486             PPCODE:
487 1           temp = PL_markstack_ptr++;
488 1           Csprintf(aTHX_ fmt, nv, size);
489 1 50         if (PL_markstack_ptr != temp) {
490             /* truly void, because dXSARGS not invoked */
491 0           PL_markstack_ptr = temp;
492 0           XSRETURN_EMPTY; /* return empty stack */
493             }
494             /* must have used dXSARGS; list context implied */
495 1           return; /* assume stack size is correct */
496              
497             int
498             _looks_like_number (x)
499             SV * x
500             CODE:
501 0           RETVAL = _looks_like_number (aTHX_ x);
502             OUTPUT: RETVAL
503