commit 3728c12ecbe308092b213f1b664303a48858a2b8
parent 56680b5fa737dd7aa1cd7446cad62f5b1da2235c
Author: Mattias Andrée <maandree@kth.se>
Date: Thu, 3 Mar 2016 12:47:39 +0100
Add zbset
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat:
13 files changed, 101 insertions(+), 2 deletions(-)
diff --git a/man/zand.3 b/man/zand.3
@@ -27,5 +27,6 @@ with non-unique parameters.
.BR zrsh (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/man/zbset.3 b/man/zbset.3
@@ -0,0 +1,39 @@
+.TH ZBSET 3 libzahl
+.SH NAME
+zbset - Set, clear, or flip a bit in a big integer
+.SH SYNOPSIS
+.nf
+#include <zahl.h>
+
+void zbset(z_t \fIa\fP, z_t \fIb\fP, size_t \fIindex\fP, int \fIset\fP);
+.fi
+.SH DESCRIPTION
+.B zbset
+either sets, clears, or flips the bit with the selected
+.I index
+in
+.IR b ,
+and stores the result in
+.IR a .
+.P
+The bit is set if
+.IR "(set>0)" ,
+clear if
+.IR "(set==0)" ,
+and flipped if
+.IR "(set<0)" .
+.P
+It is safe to call
+.B zbset
+with non-unique parameters.
+.SH SEE ALSO
+.BR zbtest (3),
+.BR zand (3),
+.BR zor (3),
+.BR zxor (3),
+.BR znot (3),
+.BR zlsh (3),
+.BR zrsh (3),
+.BR zsplit (3),
+.BR zlsb (3),
+.BR zbits (3)
diff --git a/man/zbtest.3 b/man/zbtest.3
@@ -17,6 +17,7 @@ is set in
.B zbtest
returns 1 if the bit is set, or 0 otherwise.
.SH SEE ALSO
+.BR zbset (3),
.BR zand (3),
.BR zor (3),
.BR zxor (3),
diff --git a/man/zinit.3 b/man/zinit.3
@@ -37,6 +37,7 @@ typedef struct {
.BR zbits (3),
.BR zlsb (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zand (3),
.BR zor (3),
.BR zxor (3),
diff --git a/man/zlsb.3 b/man/zlsb.3
@@ -28,5 +28,6 @@ is zero.
.SH SEE ALSO
.BR zbits (3),
.BR zbtest (3),
+.BR zbset (3),
.BR znot (3),
.BR zrsh (3)
diff --git a/man/zlsh.3 b/man/zlsh.3
@@ -28,5 +28,6 @@ with
.BR ztrunc (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/man/znot.3 b/man/znot.3
@@ -44,5 +44,6 @@ sign-and-magnitude.
.BR zrsh (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/man/zor.3 b/man/zor.3
@@ -27,5 +27,6 @@ with non-unique parameters.
.BR zrsh (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/man/zrsh.3 b/man/zrsh.3
@@ -28,5 +28,6 @@ with
.BR ztrunc (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/man/zxor.3 b/man/zxor.3
@@ -27,5 +27,6 @@ with non-unique parameters.
.BR zrsh (3),
.BR zsplit (3),
.BR zbtest (3),
+.BR zbset (3),
.BR zlsb (3),
.BR zbits (3)
diff --git a/src/zbset.c b/src/zbset.c
@@ -0,0 +1,48 @@
+/* See LICENSE file for copyright and license details. */
+#include "internals"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+void
+zbset(z_t a, z_t b, size_t bit, int action)
+{
+ zahl_char_t x = 1;
+ size_t chars;
+
+ chars = FLOOR_BITS_TO_CHARS(bit);
+ bit = BITS_IN_LAST_CHAR(bit);
+ x <<= bit;
+
+ if (a != b)
+ zset(a, b);
+
+ if (action) {
+ if (zzero(a)) {
+ a->used = 0;
+ SET_SIGNUM(a, 1);
+ }
+ if (a->used <= chars) {
+ if (a->alloced <= chars) {
+ a->alloced = chars + 1;
+ a->chars = realloc(a->chars, a->alloced * sizeof(*(a->chars)));
+ }
+ memset(a->chars + a->used, 0, (chars - a->used + 1) * sizeof(*(a->chars)));
+ }
+ }
+
+ if (action > 0) {
+ a->chars[chars] |= x;
+ return;
+ } else if (action < 0) {
+ a->chars[chars] ^= x;
+ } else if (a->used > chars) {
+ a->chars[chars] &= ~x;
+ }
+
+ while (a->used && !a->chars[a->used - 1])
+ a->used--;
+ if (!a->used)
+ SET_SIGNUM(a, 0);
+}
diff --git a/src/zbtest.c b/src/zbtest.c
@@ -9,10 +9,10 @@ zbtest(z_t a, size_t bit)
if (zzero(a))
return 0;
- chars = bit >> LB_BITS_PER_CHAR;
+ chars = FLOOR_BITS_TO_CHARS(bit);
if (chars >= a->used)
return 0;
- bit &= BITS_PER_CHAR - 1;
+ bit = BITS_IN_LAST_CHAR(bit);
return (a->chars[chars] >> bit) & 1;
}
diff --git a/zahl.h b/zahl.h
@@ -100,6 +100,9 @@ void zsplit(z_t, z_t, z_t, size_t); /* a := c >> d, b := c - (a << d) */
size_t zbits(z_t); /* ⌊log₂ |a|⌋ + 1, 1 if a = 0 */
size_t zlsb(z_t); /* Index of first set bit, SIZE_MAX if none are set. */
+/* If d > 0: a := b | (1 << c), f d = 0: a := b & ~(1 << c), if d < 0: a := b ^ (1 << c) */
+void zbset(z_t, z_t, size_t, int);
+
/* Number theory. */