119026Sjulian/* mpz_com(mpz_ptr dst, mpz_ptr src) -- Assign the bit-complemented value of
267627Sasmodai   SRC to DST.
319026Sjulian
419026SjulianCopyright 1991, 1993, 1994, 1996, 2001, 2003, 2012, 2015 Free Software
519026SjulianFoundation, Inc.
619026Sjulian
719026SjulianThis file is part of the GNU MP Library.
819026Sjulian
919026SjulianThe GNU MP Library is free software; you can redistribute it and/or modify
1019026Sjulianit under the terms of either:
1119026Sjulian
1219026Sjulian  * the GNU Lesser General Public License as published by the Free
1319026Sjulian    Software Foundation; either version 3 of the License, or (at your
1419026Sjulian    option) any later version.
1519026Sjulian
1619026Sjulianor
1719026Sjulian
1819026Sjulian  * the GNU General Public License as published by the Free Software
1919026Sjulian    Foundation; either version 2 of the License, or (at your option) any
2019026Sjulian    later version.
2119026Sjulian
2219026Sjulianor both in parallel, as here.
2319026Sjulian
2419026SjulianThe GNU MP Library is distributed in the hope that it will be useful, but
2519026SjulianWITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
2650476Speteror FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
2720920Swoschfor more details.
28264522Smav
295884SdgYou should have received copies of the GNU General Public License and the
3079538SruGNU Lesser General Public License along with the GNU MP Library.  If not,
315884Sdgsee https://www.gnu.org/licenses/.  */
325884Sdg
3313472Swollman#include "gmp-impl.h"
345884Sdg
3513472Swollmanvoid
365884Sdgmpz_com (mpz_ptr dst, mpz_srcptr src)
375884Sdg{
3868962Sru  mp_size_t size = SIZ (src);
3979727Sschweikh  mp_srcptr src_ptr;
4013472Swollman  mp_ptr dst_ptr;
4113472Swollman
4213472Swollman  if (size >= 0)
4379727Sschweikh    {
445884Sdg      /* As with infinite precision: one's complement, two's complement.
4513744Smpp	 But this can be simplified using the identity -x = ~x + 1.
4613472Swollman	 So we're going to compute (~~x) + 1 = x + 1!  */
4713472Swollman
4813472Swollman      if (UNLIKELY (size == 0))
4979727Sschweikh	{
5013472Swollman	  /* special case, as mpn_add_1 wants size!=0 */
5113472Swollman	  MPZ_NEWALLOC (dst, 1)[0] = 1;
5279727Sschweikh	  SIZ (dst) = -1;
53231244Sgjb	}
5413472Swollman      else
5540246Sken	{
565884Sdg	  mp_limb_t cy;
5713472Swollman
5813472Swollman	  dst_ptr = MPZ_REALLOC (dst, size + 1);
5979727Sschweikh
6013472Swollman	  src_ptr = PTR (src);
6157676Ssheldonh
6257676Ssheldonh	  cy = mpn_add_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
6379727Sschweikh	  dst_ptr[size] = cy;
645884Sdg	  size += cy;
656813Sdufault
6624091Smpp	  /* Store a negative size, to indicate ones-extension.  */
6724091Smpp	  SIZ (dst) = -size;
6824091Smpp      }
6913472Swollman    }
7079727Sschweikh  else
7113472Swollman    {
725884Sdg      /* As with infinite precision: two's complement, then one's complement.
7324091Smpp	 But that can be simplified using the identity -x = ~(x - 1).
7424091Smpp	 So we're going to compute ~~(x - 1) = x - 1!  */
7524091Smpp      size = -size;
766813Sdufault
776813Sdufault      dst_ptr = MPZ_REALLOC (dst, size);
786813Sdufault
795884Sdg      src_ptr = PTR (src);
805884Sdg
8113472Swollman      mpn_sub_1 (dst_ptr, src_ptr, size, (mp_limb_t) 1);
825884Sdg      size -= dst_ptr[size - 1] == 0;
8313472Swollman
8479727Sschweikh      /* Store a positive size, to indicate zero-extension.  */
8513472Swollman      SIZ (dst) = size;
865884Sdg    }
875884Sdg}
8813472Swollman