Move plugin init code
[gnumeric.git] / src / complex.c
bloba80643a9e7fbad4d38795a9084c3054484d13122
1 /*
2 * complex.c: A quick library for complex math.
4 * Author:
5 * Morten Welinder <terra@gnome.org>
6 * Jukka-Pekka Iivonen <iivonen@iki.fi>
7 */
9 #include <gnumeric-config.h>
10 #include <gnumeric.h>
11 #include <complex.h>
12 #include <gutils.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <mathfunc.h>
17 #include <sf-gamma.h>
19 /* ------------------------------------------------------------------------- */
21 char *
22 gnm_complex_to_string (gnm_complex const *src, char imunit)
24 char *re_buffer = NULL;
25 char *im_buffer = NULL;
26 char const *sign = "";
27 char const *suffix = "";
28 char *res;
29 char suffix_buffer[2];
30 const char *fmt = "%.*" GNM_FORMAT_g;
31 static int digits = -1;
33 if (digits == -1) {
34 gnm_float l10 = gnm_log10 (FLT_RADIX);
35 digits = (int)gnm_ceil (GNM_MANT_DIG * l10) +
36 (l10 == (int)l10 ? 0 : 1);
39 if (src->re != 0 || src->im == 0) {
40 /* We have a real part. */
41 re_buffer = g_strdup_printf (fmt, digits, src->re);
44 if (src->im != 0) {
45 /* We have an imaginary part. */
46 suffix = suffix_buffer;
47 suffix_buffer[0] = imunit;
48 suffix_buffer[1] = 0;
49 if (src->im == 1) {
50 if (re_buffer)
51 sign = "+";
52 } else if (src->im == -1) {
53 sign = "-";
54 } else {
55 im_buffer = g_strdup_printf (fmt, digits, src->im);
56 if (re_buffer && *im_buffer != '-' && *im_buffer != '+')
57 sign = (src->im >= 0) ? "+" : "-";
61 res = g_strconcat (re_buffer ? re_buffer : "",
62 sign,
63 im_buffer ? im_buffer : "",
64 suffix,
65 NULL);
67 g_free (re_buffer);
68 g_free (im_buffer);
70 return res;
73 /* ------------------------------------------------------------------------- */
75 #define EAT_SPACES(src_) do { \
76 while (g_unichar_isspace (g_utf8_get_char (src_))) \
77 src_ = g_utf8_next_char (src_); \
78 } while (0)
80 #define HANDLE_SIGN(src_,sign_) do { \
81 switch (*src_) { \
82 case '+': sign_ = +1; src_++; EAT_SPACES (src_); break; \
83 case '-': sign_ = -1; src_++; EAT_SPACES (src_); break; \
84 default: sign_ = 0; break; \
85 } \
86 } while (0)
88 /**
89 * gnm_complex_from_string:
90 * @dst: return location
91 * @src: string to parse
92 * @imunit: (out): return location of imaginary unit.
94 * Returns: zero on success, -1 otherwise.
96 * This function differs from Excel's parsing in at least the following
97 * ways:
98 * (1) We allow spaces before the imaginary unit used with an impled "1".
99 * Therefore we allow "+ i".
100 * (2) We do not allow a thousands separator as in "1,000i".
103 gnm_complex_from_string (gnm_complex *dst, char const *src, char *imunit)
105 gnm_float x, y;
106 char *end;
107 int sign;
109 EAT_SPACES (src);
110 HANDLE_SIGN (src, sign);
112 /* Case: "i", "+i", "-i", ... */
113 if (*src == 'i' || *src == 'j') {
114 x = 1;
115 } else {
116 x = gnm_strto (src, &end);
117 if (src == end || errno == ERANGE)
118 return -1;
119 src = end;
120 EAT_SPACES (src);
122 if (sign < 0)
123 x = 0 - x;
125 /* Case: "42", "+42", "-42", ... */
126 if (*src == 0) {
127 *dst = GNM_CREAL (x);
128 *imunit = 'i';
129 return 0;
132 /* Case: "42i", "+42i", "-42i", "-i", "i", ... */
133 if (*src == 'i' || *src == 'j') {
134 *imunit = *src++;
135 EAT_SPACES (src);
136 if (*src == 0) {
137 *dst = GNM_CMAKE (0, x);
138 return 0;
139 } else
140 return -1;
143 HANDLE_SIGN (src, sign);
144 if (!sign)
145 return -1;
147 if (*src == 'i' || *src == 'j') {
148 y = 1;
149 } else {
150 y = gnm_strto (src, &end);
151 if (src == end || errno == ERANGE)
152 return -1;
153 src = end;
154 EAT_SPACES (src);
156 if (sign < 0)
157 y = 0 - y;
159 /* Case: "42+12i", "+42-12i", "-42-12i", "-42+i", "+42-i", ... */
160 if (*src == 'i' || *src == 'j') {
161 *imunit = *src++;
162 EAT_SPACES (src);
163 if (*src == 0) {
164 *dst = GNM_CMAKE (x, y);
165 return 0;
169 return -1;
172 /* ------------------------------------------------------------------------- */
175 gnm_complex_invalid_p (gnm_complex const *src)
177 return !(gnm_finite (src->re) && gnm_finite (src->im));
180 /* ------------------------------------------------------------------------- */