/* -*- mode: objc; coding: utf-8 -*- */ /* Toilet Lisp, a Common Lisp subset for the Étoilé runtime. * Copyright (C) 2008 Matthias Andreas Benkard. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "MLKDynamicContext.h" #import "MLKInteger.h" #import "MLKPackage.h" #import "runtime-compatibility.h" #import "util.h" #import @implementation MLKInteger -(MLKInteger *) initWithMPZ:(mpz_t)mpz { self = [super init]; mpz_init_set (value, mpz); return self; } -(MLKInteger *) initWithInt:(int)intValue { self = [super init]; mpz_init_set_si (value, intValue); return self; } -(MLKInteger *) initWithIntptr_t:(intptr_t)intptr_t_value { self = [super init]; mpz_init_set_si (value, intptr_t_value); return self; } -(MLKInteger *) initWithFixnum:(id)fixnum { self = [self initWithIntptr_t:MLKIntWithFixnum(fixnum)]; return self; } -(MLKInteger *) initWithString:(NSString *)string negative:(BOOL)negative base:(unsigned int)base { self = [super init]; mpz_init_set_str (value, [string UTF8String], base); if (negative) mpz_neg (value, value); return self; } +(MLKInteger *) integerWithMPZ:(mpz_t)mpz { return AUTORELEASE ([[MLKInteger alloc] initWithMPZ:mpz]); } +(MLKInteger *) integerWithString:(NSString *)string negative:(BOOL)negative base:(unsigned int)base { return AUTORELEASE ([[MLKInteger alloc] initWithString:string negative:negative base:base]); } +(MLKInteger *) integerWithInt:(int)intValue { return AUTORELEASE ([[MLKInteger alloc] initWithInt:intValue]); } +(MLKInteger *) integerWithIntptr_t:(intptr_t)intptr_t_value { return AUTORELEASE ([[MLKInteger alloc] initWithIntptr_t:intptr_t_value]); } +(MLKInteger *) integerWithFixnum:(id)fixnum { return AUTORELEASE ([[MLKInteger alloc] initWithFixnum:fixnum]); } #define DEFINE_MPZ_TWOARG_OPERATION(SELECTOR, GMPFUN) \ DEFINE_GMP_OPERATION (SELECTOR (MLKNumber *)arg, \ mpz, \ GMPFUN (mpval, self->value, ((MLKInteger*)arg)->value), \ MLKNumber, \ MLKInteger, \ integerWithMPZ:) DEFINE_MPZ_TWOARG_OPERATION (add:, mpz_add) DEFINE_MPZ_TWOARG_OPERATION (subtract:, mpz_sub) DEFINE_MPZ_TWOARG_OPERATION (multiplyWith:, mpz_mul) DEFINE_MPZ_TWOARG_OPERATION (divideBy:, mpz_div) #define DEFINE_MPZ_TWOARG_INTONLY_OPERATION(SELECTOR, GMPFUN) \ DEFINE_GMP_OPERATION (SELECTOR (MLKInteger *)arg, \ mpz, \ GMPFUN (mpval, self->value, ((MLKInteger*)arg)->value), \ MLKInteger, \ MLKInteger, \ integerWithMPZ:) DEFINE_MPZ_TWOARG_INTONLY_OPERATION (mod:, mpz_mod) DEFINE_MPZ_TWOARG_INTONLY_OPERATION (exactlyDivideBy:, mpz_divexact) DEFINE_MPZ_TWOARG_INTONLY_OPERATION (gcd:, mpz_gcd) DEFINE_MPZ_TWOARG_INTONLY_OPERATION (lcm:, mpz_lcm) -(MLKInteger *) pow:(MLKInteger *)exponent { mpz_t mpz; mpz_t i; mpz_init_set_ui (mpz, 1); mpz_init_set (i, exponent->value); while (mpz_sgn (i) > 0) { mpz_mul (mpz, mpz, self->value); mpz_sub_ui (i, i, 1); } MLKInteger *obj = [MLKInteger integerWithMPZ:mpz]; mpz_clear (mpz); mpz_clear (i); return obj; } -(BOOL) evenp { return mpz_even_p (self->value); } -(BOOL) oddp { return mpz_odd_p (self->value); } -(MLKInteger *) isqrt { mpz_t mpz; mpz_init (mpz); mpz_sqrt (mpz, self->value); MLKInteger *obj = [MLKInteger integerWithMPZ:mpz]; mpz_clear (mpz); return obj; } -(BOOL) fitsIntoFixnum { #ifdef NO_FIXNUMS return NO; #else return (mpz_sizeinbase (self->value, 2) <= (sizeof (id)) * 8 - 2); #endif } -(id) fixnumValue { #ifdef NO_FIXNUMS return self; #else return MLKFixnumWithInt ([self intValue]); #endif } -(int) intValue { return mpz_get_si (value); } -(double) doubleValue { return mpz_get_d (value); } -(NSComparisonResult) compare:(MLKInteger *)arg { int cmp = mpz_cmp (self->value, arg->value); if (cmp == 0) return NSOrderedSame; else if (cmp < 0) return NSOrderedAscending; else return NSOrderedDescending; } -(BOOL) isEqual:(id)arg { return ([arg isKindOfClass:[MLKInteger class]] && [self compare:arg] == 0); } -(NSString *) description { return [self descriptionWithBase:10]; } -(NSString *) descriptionWithBase:(int)base { NSString *str; char cstr[mpz_sizeinbase (self->value, base) + 2]; mpz_get_str (cstr, base, self->value); str = [NSString stringWithUTF8String:cstr]; return str; } -(NSString *) descriptionForLisp { MLKInteger *base = [[MLKDynamicContext currentContext] valueForSymbol:[[MLKPackage findPackage:@"COMMON-LISP"] intern:@"*PRINT-BASE*"]]; return [self descriptionWithBase:[base intValue]]; } -(void) dealloc { mpz_clear (value); [super dealloc]; } @end