Fix 0^n generating error for fractional n
[gcalctool.git] / src / mp-binary.c
blob4c8eafb0d0560736a320b57497a3494e10e1b286
1 /*
2 * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3 * Copyright (C) 2008-2011 Robert Ancell
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
12 #include <stdio.h>
14 #include "mp.h"
15 #include "mp-private.h"
16 #include "mp-serializer.h"
18 // FIXME: Make dynamic
19 #define MAX_DIGITS 1000
21 static char digits[] = "0123456789ABCDEF";
23 static int hex_to_int(char digit)
25 if (digit >= '0' && digit <= '9')
26 return digit - '0';
27 if (digit >= 'A' && digit <= 'F')
28 return digit - 'A' + 10;
29 if (digit >= 'a' && digit <= 'f')
30 return digit - 'a' + 10;
31 return 0;
35 static gchar *
36 to_hex_string(const MPNumber *x)
38 MpSerializer *serializer;
39 gchar *result;
41 serializer = mp_serializer_new(MP_DISPLAY_FORMAT_FIXED, 16, 0);
42 result = mp_serializer_to_string(serializer, x);
43 g_object_unref(serializer);
45 return result;
49 static void
50 mp_bitwise(const MPNumber *x, const MPNumber *y, int (*bitwise_operator)(int, int), MPNumber *z, int wordlen)
52 char *text1, *text2, text_out[MAX_DIGITS], text_out2[MAX_DIGITS];
53 int offset1, offset2, offset_out;
55 text1 = to_hex_string(x);
56 text2 = to_hex_string(y);
57 offset1 = strlen(text1) - 1;
58 offset2 = strlen(text2) - 1;
59 offset_out = wordlen / 4 - 1;
60 if (offset_out <= 0) {
61 offset_out = offset1 > offset2 ? offset1 : offset2;
63 if (offset_out > 0 && (offset_out < offset1 || offset_out < offset2)) {
64 g_free(text1);
65 g_free(text2);
66 mp_set_from_integer(0, z);
67 mperr("Overflow. Try a bigger word size");
68 return;
71 /* Perform bitwise operator on each character from right to left */
72 for (text_out[offset_out+1] = '\0'; offset_out >= 0; offset_out--) {
73 int v1 = 0, v2 = 0;
75 if (offset1 >= 0) {
76 v1 = hex_to_int(text1[offset1]);
77 offset1--;
79 if (offset2 >= 0) {
80 v2 = hex_to_int(text2[offset2]);
81 offset2--;
83 text_out[offset_out] = digits[bitwise_operator(v1, v2)];
86 snprintf(text_out2, MAX_DIGITS, "%s", text_out);
87 mp_set_from_string(text_out2, 16, z);
88 g_free(text1);
89 g_free(text2);
93 static int mp_bitwise_and(int v1, int v2) { return v1 & v2; }
94 static int mp_bitwise_or(int v1, int v2) { return v1 | v2; }
95 static int mp_bitwise_xor(int v1, int v2) { return v1 ^ v2; }
96 static int mp_bitwise_not(int v1, int dummy) { return v1 ^ 0xF; }
99 bool
100 mp_is_overflow (const MPNumber *x, int wordlen)
102 MPNumber tmp1, tmp2;
103 mp_set_from_integer(2, &tmp1);
104 mp_xpowy_integer(&tmp1, wordlen, &tmp2);
105 return mp_is_greater_than (&tmp2, x);
109 void
110 mp_and(const MPNumber *x, const MPNumber *y, MPNumber *z)
112 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
114 /* Translators: Error displayed when boolean AND attempted on non-integer values */
115 mperr(_("Boolean AND is only defined for positive integers"));
118 mp_bitwise(x, y, mp_bitwise_and, z, 0);
122 void
123 mp_or(const MPNumber *x, const MPNumber *y, MPNumber *z)
125 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
127 /* Translators: Error displayed when boolean OR attempted on non-integer values */
128 mperr(_("Boolean OR is only defined for positive integers"));
131 mp_bitwise(x, y, mp_bitwise_or, z, 0);
135 void
136 mp_xor(const MPNumber *x, const MPNumber *y, MPNumber *z)
138 if (!mp_is_positive_integer(x) || !mp_is_positive_integer(y))
140 /* Translators: Error displayed when boolean XOR attempted on non-integer values */
141 mperr(_("Boolean XOR is only defined for positive integers"));
144 mp_bitwise(x, y, mp_bitwise_xor, z, 0);
148 void
149 mp_not(const MPNumber *x, int wordlen, MPNumber *z)
151 MPNumber temp;
153 if (!mp_is_positive_integer(x))
155 /* Translators: Error displayed when boolean XOR attempted on non-integer values */
156 mperr(_("Boolean NOT is only defined for positive integers"));
159 mp_set_from_integer(0, &temp);
160 mp_bitwise(x, &temp, mp_bitwise_not, z, wordlen);
164 void
165 mp_mask(const MPNumber *x, int wordlen, MPNumber *z)
167 char *text;
168 size_t len, offset;
170 /* Convert to a hexadecimal string and use last characters */
171 text = to_hex_string(x);
172 len = strlen(text);
173 offset = wordlen / 4;
174 offset = len > offset ? len - offset: 0;
175 mp_set_from_string(text + offset, 16, z);
176 g_free(text);
180 void
181 mp_shift(const MPNumber *x, int count, MPNumber *z)
183 int i, multiplier = 1;
185 if (!mp_is_integer(x)) {
186 /* Translators: Error displayed when bit shift attempted on non-integer values */
187 mperr(_("Shift is only possible on integer values"));
188 return;
191 if (count >= 0) {
192 for (i = 0; i < count; i++)
193 multiplier *= 2;
194 mp_multiply_integer(x, multiplier, z);
196 else {
197 MPNumber temp;
198 for (i = 0; i < -count; i++)
199 multiplier *= 2;
200 mp_divide_integer(x, multiplier, &temp);
201 mp_floor(&temp, z);
206 void
207 mp_ones_complement(const MPNumber *x, int wordlen, MPNumber *z)
209 MPNumber t;
210 mp_set_from_integer(0, &t);
211 mp_bitwise(x, &t, mp_bitwise_xor, z, wordlen);
212 mp_not(z, wordlen, z);
216 void
217 mp_twos_complement(const MPNumber *x, int wordlen, MPNumber *z)
219 mp_ones_complement (x, wordlen, z);
220 mp_add_integer (z, 1, z);