srfi-60.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /* srfi-60.c --- Integers as Bits
  2. *
  3. * Copyright (C) 2005, 2006, 2008, 2010 Free Software Foundation, Inc.
  4. *
  5. * This library is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU Lesser General Public License
  7. * as published by the Free Software Foundation; either version 3 of
  8. * the License, or (at your option) any later version.
  9. *
  10. * This library is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * Lesser General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with this library; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18. * 02110-1301 USA
  19. */
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23. #include "libguile/_scm.h"
  24. #include "libguile/eq.h"
  25. #include "libguile/validate.h"
  26. #include "libguile/numbers.h"
  27. #include "libguile/srfi-60.h"
  28. SCM_DEFINE (scm_srfi60_log2_binary_factors, "log2-binary-factors", 1, 0, 0,
  29. (SCM n),
  30. "Return a count of how many factors of 2 are present in @var{n}.\n"
  31. "This is also the bit index of the lowest 1 bit in @var{n}. If\n"
  32. "@var{n} is 0, the return is @math{-1}.\n"
  33. "\n"
  34. "@example\n"
  35. "(log2-binary-factors 6) @result{} 1\n"
  36. "(log2-binary-factors -8) @result{} 3\n"
  37. "@end example")
  38. #define FUNC_NAME s_scm_srfi60_log2_binary_factors
  39. {
  40. SCM ret = SCM_EOL;
  41. if (SCM_I_INUMP (n))
  42. {
  43. long nn = SCM_I_INUM (n);
  44. if (nn == 0)
  45. return SCM_I_MAKINUM (-1);
  46. nn = nn ^ (nn-1); /* 1 bits for each low 0 and lowest 1 */
  47. return scm_logcount (SCM_I_MAKINUM (nn >> 1));
  48. }
  49. else if (SCM_BIGP (n))
  50. {
  51. /* no need for scm_remember_upto_here_1 here, mpz_scan1 doesn't do
  52. anything that could result in a gc */
  53. return SCM_I_MAKINUM (mpz_scan1 (SCM_I_BIG_MPZ (n), 0L));
  54. }
  55. else
  56. SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
  57. return ret;
  58. }
  59. #undef FUNC_NAME
  60. SCM_DEFINE (scm_srfi60_copy_bit, "copy-bit", 3, 0, 0,
  61. (SCM index, SCM n, SCM newbit),
  62. "Return @var{n} with the bit at @var{index} set according to\n"
  63. "@var{newbit}. @var{newbit} should be @code{#t} to set the bit\n"
  64. "to 1, or @code{#f} to set it to 0. Bits other than at\n"
  65. "@var{index} are unchanged in the return.\n"
  66. "\n"
  67. "@example\n"
  68. "(copy-bit 1 #b0101 #t) @result{} 7\n"
  69. "@end example")
  70. #define FUNC_NAME s_scm_srfi60_copy_bit
  71. {
  72. SCM r;
  73. unsigned long ii;
  74. int bb;
  75. ii = scm_to_ulong (index);
  76. bb = scm_to_bool (newbit);
  77. if (SCM_I_INUMP (n))
  78. {
  79. long nn = SCM_I_INUM (n);
  80. /* can't set high bit ii==SCM_LONG_BIT-1, that would change the sign,
  81. which is not what's wanted */
  82. if (ii < SCM_LONG_BIT-1)
  83. {
  84. nn &= ~(1L << ii); /* zap bit at index */
  85. nn |= ((long) bb << ii); /* insert desired bit */
  86. return scm_from_long (nn);
  87. }
  88. else
  89. {
  90. /* bits at ii==SCM_LONG_BIT-1 and above are all copies of the sign
  91. bit, if this is already the desired "bit" value then no need to
  92. make a new bignum value */
  93. if (bb == (nn < 0))
  94. return n;
  95. r = scm_i_long2big (nn);
  96. goto big;
  97. }
  98. }
  99. else if (SCM_BIGP (n))
  100. {
  101. /* if the bit is already what's wanted then no need to make a new
  102. bignum */
  103. if (bb == mpz_tstbit (SCM_I_BIG_MPZ (n), ii))
  104. return n;
  105. r = scm_i_clonebig (n, 1);
  106. big:
  107. if (bb)
  108. mpz_setbit (SCM_I_BIG_MPZ (r), ii);
  109. else
  110. mpz_clrbit (SCM_I_BIG_MPZ (r), ii);
  111. /* changing a high bit might put the result into range of a fixnum */
  112. return scm_i_normbig (r);
  113. }
  114. else
  115. SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
  116. }
  117. #undef FUNC_NAME
  118. SCM_DEFINE (scm_srfi60_rotate_bit_field, "rotate-bit-field", 4, 0, 0,
  119. (SCM n, SCM count, SCM start, SCM end),
  120. "Return @var{n} with the bit field from @var{start} (inclusive)\n"
  121. "to @var{end} (exclusive) rotated upwards by @var{count} bits.\n"
  122. "\n"
  123. "@var{count} can be positive or negative, and it can be more\n"
  124. "than the field width (it'll be reduced modulo the width).\n"
  125. "\n"
  126. "@example\n"
  127. "(rotate-bit-field #b0110 2 1 4) @result{} #b1010\n"
  128. "@end example")
  129. #define FUNC_NAME s_scm_srfi60_rotate_bit_field
  130. {
  131. unsigned long ss = scm_to_ulong (start);
  132. unsigned long ee = scm_to_ulong (end);
  133. unsigned long ww, cc;
  134. SCM_ASSERT_RANGE (3, end, (ee >= ss));
  135. ww = ee - ss;
  136. cc = scm_to_ulong (scm_modulo (count, scm_difference (end, start)));
  137. if (SCM_I_INUMP (n))
  138. {
  139. long nn = SCM_I_INUM (n);
  140. if (ee <= SCM_LONG_BIT-1)
  141. {
  142. /* all within a long */
  143. long below = nn & ((1L << ss) - 1); /* before start */
  144. long above = nn & (-1L << ee); /* above end */
  145. long fmask = (-1L << ss) & ((1L << ee) - 1); /* field mask */
  146. long ff = nn & fmask; /* field */
  147. return scm_from_long (above
  148. | ((ff << cc) & fmask)
  149. | ((ff >> (ww-cc)) & fmask)
  150. | below);
  151. }
  152. else
  153. {
  154. /* either no movement, or a field of only 0 or 1 bits, result
  155. unchanged, avoid creating a bignum */
  156. if (cc == 0 || ww <= 1)
  157. return n;
  158. n = scm_i_long2big (nn);
  159. goto big;
  160. }
  161. }
  162. else if (SCM_BIGP (n))
  163. {
  164. mpz_t tmp;
  165. SCM r;
  166. /* either no movement, or in a field of only 0 or 1 bits, result
  167. unchanged, avoid creating a new bignum */
  168. if (cc == 0 || ww <= 1)
  169. return n;
  170. big:
  171. r = scm_i_ulong2big (0);
  172. mpz_init (tmp);
  173. /* portion above end */
  174. mpz_fdiv_q_2exp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (n), ee);
  175. mpz_mul_2exp (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), ee);
  176. /* field high part, width-count bits from start go to start+count */
  177. mpz_fdiv_q_2exp (tmp, SCM_I_BIG_MPZ (n), ss);
  178. mpz_fdiv_r_2exp (tmp, tmp, ww - cc);
  179. mpz_mul_2exp (tmp, tmp, ss + cc);
  180. mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
  181. /* field high part, count bits from end-count go to start */
  182. mpz_fdiv_q_2exp (tmp, SCM_I_BIG_MPZ (n), ee - cc);
  183. mpz_fdiv_r_2exp (tmp, tmp, cc);
  184. mpz_mul_2exp (tmp, tmp, ss);
  185. mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
  186. /* portion below start */
  187. mpz_fdiv_r_2exp (tmp, SCM_I_BIG_MPZ (n), ss);
  188. mpz_ior (SCM_I_BIG_MPZ (r), SCM_I_BIG_MPZ (r), tmp);
  189. mpz_clear (tmp);
  190. /* bits moved around might leave us in range of an inum */
  191. return scm_i_normbig (r);
  192. }
  193. else
  194. SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
  195. }
  196. #undef FUNC_NAME
  197. SCM_DEFINE (scm_srfi60_reverse_bit_field, "reverse-bit-field", 3, 0, 0,
  198. (SCM n, SCM start, SCM end),
  199. "Return @var{n} with the bits between @var{start} (inclusive) to\n"
  200. "@var{end} (exclusive) reversed.\n"
  201. "\n"
  202. "@example\n"
  203. "(reverse-bit-field #b101001 2 4) @result{} #b100101\n"
  204. "@end example")
  205. #define FUNC_NAME s_scm_srfi60_reverse_bit_field
  206. {
  207. long ss = scm_to_long (start);
  208. long ee = scm_to_long (end);
  209. long swaps = (ee - ss) / 2; /* number of swaps */
  210. SCM b;
  211. if (SCM_I_INUMP (n))
  212. {
  213. long nn = SCM_I_INUM (n);
  214. if (ee <= SCM_LONG_BIT-1)
  215. {
  216. /* all within a long */
  217. long smask = 1L << ss;
  218. long emask = 1L << (ee-1);
  219. for ( ; swaps > 0; swaps--)
  220. {
  221. long sbit = nn & smask;
  222. long ebit = nn & emask;
  223. nn ^= sbit ^ (ebit ? smask : 0) /* zap sbit, put ebit value */
  224. ^ ebit ^ (sbit ? emask : 0); /* zap ebit, put sbit value */
  225. smask <<= 1;
  226. emask >>= 1;
  227. }
  228. return scm_from_long (nn);
  229. }
  230. else
  231. {
  232. /* avoid creating a new bignum if reversing only 0 or 1 bits */
  233. if (ee - ss <= 1)
  234. return n;
  235. b = scm_i_long2big (nn);
  236. goto big;
  237. }
  238. }
  239. else if (SCM_BIGP (n))
  240. {
  241. /* avoid creating a new bignum if reversing only 0 or 1 bits */
  242. if (ee - ss <= 1)
  243. return n;
  244. b = scm_i_clonebig (n, 1);
  245. big:
  246. ee--;
  247. for ( ; swaps > 0; swaps--)
  248. {
  249. int sbit = mpz_tstbit (SCM_I_BIG_MPZ (b), ss);
  250. int ebit = mpz_tstbit (SCM_I_BIG_MPZ (b), ee);
  251. if (sbit ^ ebit)
  252. {
  253. /* the two bits are different, flip them */
  254. if (sbit)
  255. {
  256. mpz_clrbit (SCM_I_BIG_MPZ (b), ss);
  257. mpz_setbit (SCM_I_BIG_MPZ (b), ee);
  258. }
  259. else
  260. {
  261. mpz_setbit (SCM_I_BIG_MPZ (b), ss);
  262. mpz_clrbit (SCM_I_BIG_MPZ (b), ee);
  263. }
  264. }
  265. ss++;
  266. ee--;
  267. }
  268. /* swapping zero bits into the high might make us fit a fixnum */
  269. return scm_i_normbig (b);
  270. }
  271. else
  272. SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
  273. }
  274. #undef FUNC_NAME
  275. SCM_DEFINE (scm_srfi60_integer_to_list, "integer->list", 1, 1, 0,
  276. (SCM n, SCM len),
  277. "Return bits from @var{n} in the form of a list of @code{#t} for\n"
  278. "1 and @code{#f} for 0. The least significant @var{len} bits\n"
  279. "are returned, and the first list element is the most\n"
  280. "significant of those bits. If @var{len} is not given, the\n"
  281. "default is @code{(integer-length @var{n})} (@pxref{Bitwise\n"
  282. "Operations}).\n"
  283. "\n"
  284. "@example\n"
  285. "(integer->list 6) @result{} (#t #t #f)\n"
  286. "(integer->list 1 4) @result{} (#f #f #f #t)\n"
  287. "@end example")
  288. #define FUNC_NAME s_scm_srfi60_integer_to_list
  289. {
  290. SCM ret = SCM_EOL;
  291. unsigned long ll, i;
  292. if (SCM_UNBNDP (len))
  293. len = scm_integer_length (n);
  294. ll = scm_to_ulong (len);
  295. if (SCM_I_INUMP (n))
  296. {
  297. long nn = SCM_I_INUM (n);
  298. for (i = 0; i < ll; i++)
  299. {
  300. unsigned long shift =
  301. (i < ((unsigned long) SCM_LONG_BIT-1))
  302. ? i : ((unsigned long) SCM_LONG_BIT-1);
  303. int bit = (nn >> shift) & 1;
  304. ret = scm_cons (scm_from_bool (bit), ret);
  305. }
  306. }
  307. else if (SCM_BIGP (n))
  308. {
  309. for (i = 0; i < ll; i++)
  310. ret = scm_cons (scm_from_bool (mpz_tstbit (SCM_I_BIG_MPZ (n), i)),
  311. ret);
  312. scm_remember_upto_here_1 (n);
  313. }
  314. else
  315. SCM_WRONG_TYPE_ARG (SCM_ARG1, n);
  316. return ret;
  317. }
  318. #undef FUNC_NAME
  319. SCM_DEFINE (scm_srfi60_list_to_integer, "list->integer", 1, 0, 0,
  320. (SCM lst),
  321. "Return an integer formed bitwise from the given @var{lst} list\n"
  322. "of booleans. Each boolean is @code{#t} for a 1 and @code{#f}\n"
  323. "for a 0. The first element becomes the most significant bit in\n"
  324. "the return.\n"
  325. "\n"
  326. "@example\n"
  327. "(list->integer '(#t #f #t #f)) @result{} 10\n"
  328. "@end example")
  329. #define FUNC_NAME s_scm_srfi60_list_to_integer
  330. {
  331. long len;
  332. /* strip high zero bits from lst; after this the length tells us whether
  333. an inum or bignum is required */
  334. while (scm_is_pair (lst) && scm_is_false (SCM_CAR (lst)))
  335. lst = SCM_CDR (lst);
  336. SCM_VALIDATE_LIST_COPYLEN (SCM_ARG1, lst, len);
  337. if (len <= SCM_I_FIXNUM_BIT - 1)
  338. {
  339. /* fits an inum (a positive inum) */
  340. long n = 0;
  341. while (scm_is_pair (lst))
  342. {
  343. n <<= 1;
  344. if (! scm_is_false (SCM_CAR (lst)))
  345. n++;
  346. lst = SCM_CDR (lst);
  347. }
  348. return SCM_I_MAKINUM (n);
  349. }
  350. else
  351. {
  352. /* need a bignum */
  353. SCM n = scm_i_ulong2big (0);
  354. while (scm_is_pair (lst))
  355. {
  356. len--;
  357. if (! scm_is_false (SCM_CAR (lst)))
  358. mpz_setbit (SCM_I_BIG_MPZ (n), len);
  359. lst = SCM_CDR (lst);
  360. }
  361. return n;
  362. }
  363. }
  364. #undef FUNC_NAME
  365. /* note: don't put "scm_srfi60_list_to_integer" arg on its own line, a
  366. newline breaks the snarfer */
  367. SCM_REGISTER_PROC (s_srfi60_booleans_to_integer, "booleans->integer", 0, 0, 1, scm_srfi60_list_to_integer);
  368. void
  369. scm_register_srfi_60 (void)
  370. {
  371. scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
  372. "scm_init_srfi_60",
  373. (scm_t_extension_init_func)scm_init_srfi_60, NULL);
  374. }
  375. void
  376. scm_init_srfi_60 (void)
  377. {
  378. #ifndef SCM_MAGIC_SNARFER
  379. #include "libguile/srfi-60.x"
  380. #endif
  381. }