Package abstrasy.libraries.math

Source Code of abstrasy.libraries.math.External_Integer

package abstrasy.libraries.math;


import abstrasy.Bivalence;
import abstrasy.Buffer;
import abstrasy.Bytes;
import abstrasy.Node;
import abstrasy.PCoder;
import abstrasy.SELF;

import abstrasy.externals.AExtCachable;
import abstrasy.externals.AExtClonable;
import abstrasy.externals.AExtTools;
import abstrasy.externals.AExtVObject;

import abstrasy.interpreter.InterpreterException;
import abstrasy.interpreter.ORef;
import abstrasy.interpreter.StdErrors;

import abstrasy.libraries.io.External_Buffer;
import abstrasy.libraries.math.rjm.BigIntegerMath;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;

import java.util.concurrent.atomic.AtomicReference;


/**
* Abstrasy Interpreter
*
* Copyright : Copyright (c) 2006-2012, Luc Bruninx.
*
* Concédée sous licence EUPL, version 1.1 uniquement (la «Licence»).
*
* Vous ne pouvez utiliser la présente oeuvre que conformément à la Licence.
* Vous pouvez obtenir une copie de la Licence à l’adresse suivante:
*
*   http://www.osor.eu/eupl
*
* Sauf obligation légale ou contractuelle écrite, le logiciel distribué sous
* la Licence est distribué "en l’état", SANS GARANTIES OU CONDITIONS QUELLES
* QU’ELLES SOIENT, expresses ou implicites.
*
* Consultez la Licence pour les autorisations et les restrictions
* linguistiques spécifiques relevant de la Licence.
*
*
* @author Luc Bruninx
* @version 1.0
*/

public class External_Integer extends AExtTools implements AExtClonable,
        AExtCachable,
        AExtVObject {

    /* Nombre */
    private AtomicReference<BigInteger> number = new AtomicReference<BigInteger>(BigInteger.ZERO);


    //private BigInteger number = BigInteger.ZERO;

    /**
     * Constructeur par défaut
     */
    public External_Integer() {
    }

    public External_Integer(BigInteger number) {
        this.number.getAndSet(number);
    }

    /**
     * Méthode implémentation du clonage
     * @param bival
     * @return
     */
    @Override
    public Object clone_my_self(Bivalence bival) {
        External_Integer t = new External_Integer();
        BigInteger n = BigInteger.ZERO;
        t.number.getAndSet(n.add(number.get()));
        return t;
    }

    /**
     * Implémentation de la méthode init!:
     * - ((new Math:Integer) 'init! x) où (:init! x) est équivalent à (:parse! x)
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_init(Node startAt) throws Exception {
        external_mutator_parse(startAt);
        return SELF.get(); // retourner une référence de l'objet courrant...
    }

    /**
     * Sérialisation du Integer...
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_quote(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1, 2);
        Node res = null;
        res = abstrasy.externals.AExtTools.SerializationTK.createInitExpr(Node.createPattern(External_Integer.class.getName()), new Node(number.get().toString()));
        return res;
    }


    /*
     *
     */

    private final static double LONG_MAX_VALUE = Long.MAX_VALUE;
    private final static double LONG_MIN_VALUE = Long.MIN_VALUE;
   
   

    private final BigInteger _convertArg_(Node arg) throws Exception {
       
        long qt=arg.getQType();
       
        if (qt==Node.TYPE_NUMBER) {
            //number
            double rint = arg.getNumber();
            if (rint < LONG_MAX_VALUE && rint > LONG_MIN_VALUE)
                return BigInteger.valueOf(Math.round(rint));
            else
                return new BigInteger("" + Math.rint(arg.getNumber()));
        }
       
       
        else if (qt==Node.TYPE_STRING) {
            //string
            String r = Node.node2VString(arg).getString();
            if (r.startsWith("0x"))
                return new BigInteger(r.substring(2), 16);
            else if (r.startsWith("0o"))
                return new BigInteger(r.substring(2), 8);
            else if (r.startsWith("0b"))
                return new BigInteger(r.substring(2), 2);
            else if (r.startsWith("-0x"))
                return new BigInteger(r.substring(3), 16).negate();
            else if (r.startsWith("-0o"))
                return new BigInteger(r.substring(3), 8).negate();
            else if (r.startsWith("-0b"))
                return new BigInteger(r.substring(3), 2).negate();
            else
                return new BigInteger(r);
        }
       
        else if (qt==Node.TYPE_BYTES) {
            //bytes
            return new BigInteger(arg.getBytes().getArray());
        }
       
        else if (arg.isDelegable()) {

            if (arg.getQType() == Node.TYPE_EXTERNAL) {
                Object o = arg.getExternal();
                // tester d'abord les optimisations
                if (o instanceof External_Integer)
                    // optimisation pour Integer
                    return ((External_Integer) o).number.get();
                else if (o instanceof External_Decimal)
                    // optimisation pour Decimal
                    return ((External_Decimal) o).toInteger();
            }

            // pas d'optimisation...
            // résolution générale...

            // (:to-integer)
            Node r = Node.VDelegable.evalMethod_or_null(arg, "to-integer", null);
            if (r != null)
                return _convertArg_(r);

            // (:bytes)
            r = Node.VDelegable.evalMethod_or_null(arg, PCoder.getMethod(PCoder.PC_BYTES), null);
            if (r != null)
                return _convertArg_(r);
           
            // (:number)
            r = Node.VDelegable.evalMethod_or_null(arg,PCoder.getMethod(PCoder.PC_NUMBER), null);
            if (r != null)
                return _convertArg_(r);
           
            // (:string)
            r = Node.VDelegable.evalMethod_or_null(arg, PCoder.getMethod(PCoder.PC_STRING), null);
            if (r != null)
                return _convertArg_(r);

        }

        // sinon, et bien...
        throw new InterpreterException(StdErrors.extend(StdErrors.Invalid_parameter, "This object do not implement :to-integer method (" + arg.toString() + ")"));

    }

    private final BigInteger _getArg_(Node startAt, int i) throws Exception {
        return _convertArg_(startAt.getSubNode(i, Node.TYPE_NUMBER | Node.TYPE_BYTES | Node.TYPE_STRING | Node.VTYPE_DELEGABLE));
    }

    /*
     *
     */

    private final BigInteger _getArg_lazy_(Node startAt, int i) throws Exception {
        return _convertArg_(startAt.getSubNode_LazyValue(i, Node.TYPE_NUMBER | Node.TYPE_BYTES | Node.TYPE_STRING | Node.VTYPE_DELEGABLE));

    }

    /*
     *
     */


    /**
     * Analyseur / convertiseur vers le type Integer.
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_parse(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        SELF.require_SELF_mutable();
        number.getAndSet(_getArg_(startAt, 1));
        return null;
    }

    public Node external_mutator_from_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        Buffer buffer = ((External_Buffer) AExtTools.getArgExternalInstance(startAt, 1, External_Buffer.class, Node.ACCESSVTYPE_MUTABLE_WRITELOCK)).getBuffer();
        if (buffer.length() > 0)
            number.getAndSet(new BigInteger(buffer.read_bytes()));
        else
            number.getAndSet(BigInteger.ZERO);
        return null;
    }

   
    public Node external_to_buffer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        Buffer buffer = new Buffer();
        buffer.write_bytes(number.get().toByteArray());
        External_Buffer res = new External_Buffer();
        res.setBuffer(buffer);
        return Node.createExternal(res);
    }

    public Node external_bytes(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        Bytes buffer = new Bytes(number.get().toByteArray());
        return Node.createBytes(buffer);
    }

    /**
     * Retourne le Decimal sous la forme d'un number.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_number(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().doubleValue());
    }


    /**
     * Retourne le Decimal sous la forme d'une chaîne de caractères dans la forme complète.
     *
     * @param startAt
     * @return Node:string
     * @throws Exception
     */
    public Node external_string(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().toString());
    }

    /**
     * Retourne l'Integer sous la forme d'une chaîne de caractères dans la Engineering (avec puissances de 10).
     *
     * @param startAt
     * @return Node:string
     * @throws Exception
     */
    public Node external_string_E(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(new BigDecimal(number.get(), External_Context.context).toEngineeringString());
    }

    /**
     * retourne le nombre exprimé sous la forme d'une chaîne hexadécimale
     *
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_hex_string(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().toString(16));
    }

    /**
     * retourne le nombre exprimé sous la forme d'une chaîne octale
     *
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_oct_string(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().toString(8));
    }

    /**
     * retourne le nombre exprimé sous la forme d'une chaîne octale
     *
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_bin_string(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().toString(2));
    }

    /**
     * méthode réservée pour faciliter la conversion des types...
     *
     * @return BigDecimal
     */
    public BigDecimal toDecimal() {
        String sn = number.get().toString();
        MathContext mc = new MathContext(External_Context.context.getPrecision() + sn.length(), External_Context.context.getRoundingMode());
        return new BigDecimal(sn, mc);
    }

    /**
     * retourne un Node:Decimal qui correspond au nombre courant.
     *
     * @param startAt
     * @return Node:Decimal
     * @throws Exception
     */
    public Node external_to_decimal(Node startAt) throws Exception {
        String sn = number.get().toString();
        MathContext mc = new MathContext(External_Context.context.getPrecision() + sn.length(), External_Context.context.getRoundingMode());
        return Node.createExternal(new External_Decimal(new BigDecimal(sn, mc), mc));
    }

    /**
     * Retourne un Node:number -1, si l'élément comparé est plus petit, 1 si l'élément comparé est plus grand, et 0 s'il s'ont de valeur
     * égale.
     *
     * Est utilisé par =?, >?, <?, <=?, =>? et <>?....
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_compare(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        return new Node(number.get().compareTo(_getArg_(startAt, 1)));
    }

    public Node external_is_equ(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        return new Node(number.get().equals(_getArg_(startAt, 1)) ? Node.TRUE:Node.FALSE);
    }
   
    /**
     * retourne la valeur absolue du nombre.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_abs(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return Node.createExternal(new External_Integer(number.get().abs()));
    }

    /**
     * retourne un Node:nombre -1, 0 ou 1 selon que la valeur soit négative, nulle ou positive.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_sgn(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().signum());
    }

    /**
     * retourne TRUE si la valeur du nombre est zéro.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_zero(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().signum() == 0 ? Node.TRUE: Node.FALSE);
    }

    /**
     * retourne TRUE si le nombre est négatif.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_negative(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().signum() < 0 ? Node.TRUE: Node.FALSE);
    }

    /**
     * retourne TRUE si le nombre est positif.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_is_positive(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().signum() > 0 ? Node.TRUE: Node.FALSE);
    }

    /**
     * retourne TRUE si le nombre est impaire.
     *
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_odd(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        BigInteger a = number.get().remainder(BigIntegerMath.TWO);
        return new Node(a.compareTo(BigInteger.ONE) != 0 ? Node.TRUE: Node.FALSE);
    }

    /**
     * retourne TRUE si la valeur entière du nombre est paire.
     *
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_even(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        BigInteger a = number.get().remainder(BigIntegerMath.TWO);
        return new Node(a.compareTo(BigInteger.ONE) == 0 ? Node.TRUE: Node.FALSE);
    }

    /**
     * retourne toujours TRUE (le nombre est toujours un entier)
     *
     * Cette méthode est définie pour assurer le polymorphisme.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_integer(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(Node.TRUE);
    }

    /**
     * retourne toujours FALSE (le nombre est toujours un entier).
     *
     * Cette méthode est définie pour assurer le polymorphisme.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_is_decimal(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(Node.FALSE);
    }

    /**
     * retourne un Node:nombre indiquant le nombre de chiffres (puissance de 10 du Decimal).
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_digits10(Node startAt) throws Exception {
        return new Node(BigIntegerMath.digits10(number.get()));
    }

    /**
     * Retourne la valeur du bit dont les positions est fournie.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_is_bit(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        return new Node(number.get().testBit((int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber()) ? Node.TRUE: Node.FALSE);
    }

    /**
     * Retourne le nombre de bits minimum pour représenter le nombre.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_digits2(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return new Node(number.get().bitLength());
    }

    /**
     * Retourne un Integer dans lequel les bits dont les positions sont fournies en argument ont été placés à 1.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_set_bits(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        for (int i = 1; i < startAt.size(); i++) {
            r = r.setBit((int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber());
        }
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * Place les bits dont la position est idiquée à 1 dans l' Integer courrant.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_set_bits(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        int[] bits = new int[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            bits[i - 1] = (int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber();
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < bits.length; i++)
                r = r.setBit(bits[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * Place les bits dont la position est idiquée à 1 dans l' Integer courrant.
     *
     * Comme il s'agit d'une fonction fetch-and-*, la valeur de l'entier est retournée
     * dans son état d'avant la modificetion.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_set_bits(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        int[] bits = new int[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            bits[i - 1] = (int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber();
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < bits.length; i++)
                r = r.setBit(bits[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne un Integer dans lequel les bits dont les positions sont fournies en argument ont été placés à 0.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_clear_bits(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        for (int i = 1; i < startAt.size(); i++) {
            r = r.clearBit((int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber());
        }
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * Place les bits dont la position est idiquée à 1 dans l' Integer courrant.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_clear_bits(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        int[] bits = new int[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            bits[i - 1] = (int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber();
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < bits.length; i++)
                r = r.clearBit(bits[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * Place les bits dont la position est idiquée à 1 dans l' Integer courrant.
     *
     * Les types d'entrées supportées sont: number
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_clear_bits(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        int[] bits = new int[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            bits[i - 1] = (int) startAt.getSubNode(i, Node.TYPE_NUMBER).getNumber();
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < bits.length; i++)
                r = r.clearBit(bits[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne la somme du Integer courant ajouté de la liste de valeurs qui peuvent être des Nodes.
     *
     * Les types d'entrées supportées sont: number, string, Integer, Decimal.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_add(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        for (int i = 1; i < startAt.size(); i++) {
            r = r.add(_getArg_(startAt, i));
        }
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur +!
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_add(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.add(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&+!
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_fetch_and_add(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.add(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne le produit du Integer courant multiplié par la liste des valeurs posées en arguments.
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mul(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        if (r.signum() == 0) {
            // cas ou la variable statique est déjà zéro.
            return Node.createExternal(new External_Integer(BigInteger.ZERO));
        }
        int i = 1;
        int asize = startAt.size();
        while (i < asize && r.signum() != 0)
            r = r.multiply(_getArg_lazy_(startAt, i++));
        //System.out.println("ml:"+r.toString());
        // signum() retourne 0 si r vaut 0. Cette méthode est plus rapide que compareTo()...
        return Node.createExternal(new External_Integer(r));
    }


    /*
     * Pour expérimentation... tests de debogage...
     *
     public Node externalpc_test(){
        return Node.createEmptyList();
    }
     */


    /**
     * surcharge de l'opérateur *!
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_mul(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        if (number.get().signum() == 0) {
            // cas ou la variable statique est déjà zéro.
            return null;
        }
        BigInteger v = BigInteger.ONE;
        int ki = 1;
        while (ki < startAt.size()) {
            v = v.multiply(_getArg_lazy_(startAt, ki++));
            if (v.signum() == 0)
                ki = startAt.size();
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            int i = 0;
            r = r.multiply(v);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * Surcharge de l'opérateur fetch&*!
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_fetch_and_mul(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        if (number.get().signum() == 0) {
            // cas ou la variable statique est déjà zéro.
            return Node.createExternal(new External_Integer(BigInteger.ZERO));
        }
        BigInteger v = BigInteger.ONE;
        int ki = 1;
        while (ki < startAt.size()) {
            v = v.multiply(_getArg_lazy_(startAt, ki++));
            if (v.signum() == 0)
                ki = startAt.size();
        }

        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            r = r.multiply(v);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne le reste de la division entière de la valeur courante avec l'argument.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mod(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        try {
            return Node.createExternal(new External_Integer(number.get().remainder(_getArg_(startAt, 1))));
        }
        catch (ArithmeticException ex) {
            // prévoir la gestion de l'exception division par zéro sur exception seulement.
            // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
            if (ex.getMessage().equals("Division by zero")) {
                throw new InterpreterException(StdErrors.Division_by_zero);
            }
            else {
                throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
            }
        }
    }

    /**
     * Retourne le résultat de la soustraction des valeurs d'entrées à partir de la valeur courante.
     *
     * Note: S'il n'y a pas d'arguments, la méthode retourne -n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_sub(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        int asize = startAt.size();
        if (asize == 1) {
            return Node.createExternal(new External_Integer(number.get().negate()));
        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        BigInteger r = number.get();
        for (int i = 1; i < asize; )
            r = r.subtract(_getArg_(startAt, i++));
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur -!
     *
     * Note: S'il n'y a pas d'arguments, la méthode effectue l'opération -n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_sub(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        SELF.require_SELF_mutable();
        int asize = startAt.size();
        if (asize == 1) {
            BigInteger old_r;
            BigInteger r;
            do {
                old_r = number.get();
                r = old_r.negate();
            }
            while (!number.compareAndSet(old_r, r));
            return null;
        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.subtract(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * Surcharge de l'opérateur fetch&-!
     *
     * Note: S'il n'y a pas d'arguments, la méthode effectue l'opération -n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont: number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_fetch_and_sub(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        SELF.require_SELF_mutable();
        int asize = startAt.size();
        if (asize == 1) {
            BigInteger old_r;
            BigInteger r;
            do {
                old_r = number.get();
                r = old_r.negate();
            }
            while (!number.compareAndSet(old_r, r));
            return Node.createExternal(new External_Integer(old_r));
        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.subtract(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Renvoie le résultat de la division (entière) successive des arguments à partir de la valeur courante.
     *
     * Note: S'il n'y à pas d'argument, la méthode retourne le résultat de l'opération 1/n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont : number, string, Integer et Decimal.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_div(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        int asize = startAt.size();
        if (asize == 1) {
            BigInteger d = BigInteger.ONE;

            try {
                return Node.createExternal(new External_Integer(d.divide(number.get())));
            }
            catch (ArithmeticException ex) {
                // prévoir la gestion de l'exception division par zéro sur exception seulement.
                // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
                if (ex.getMessage().equals("Division by zero")) {
                    throw new InterpreterException(StdErrors.Division_by_zero);
                }
                else {
                    throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
                }
            }
        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        BigInteger r = number.get();
        try {
            for (int i = 1; i < asize; )
                r = r.divide(_getArg_(startAt, i++));
        }
        catch (ArithmeticException ex) {
            // prévoir la gestion de l'exception division par zéro sur exception seulement.
            // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
            if (ex.getMessage().equals("Division by zero")) {
                throw new InterpreterException(StdErrors.Division_by_zero);
            }
            else {
                throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
            }
        }
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur /!
     *
     * Note: S'il n'y à pas d'argument, la méthode effectue de l'opération 1/n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont : number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_div(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        SELF.require_SELF_mutable();
        int asize = startAt.size();
        if (asize == 1) {
            BigInteger d = BigInteger.ONE;
            try {
                BigInteger old_r;
                BigInteger r;
                do {
                    old_r = number.get();
                    r = d.divide(old_r);
                }
                while (!number.compareAndSet(old_r, r));
            }
            catch (ArithmeticException ex) {
                // prévoir la gestion de l'exception division par zéro sur exception seulement.
                // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
                if (ex.getMessage().equals("Division by zero")) {
                    throw new InterpreterException(StdErrors.Division_by_zero);
                }
                else {
                    throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
                }
            }
            return null;
        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        try {
            BigInteger[] v = new BigInteger[startAt.size() - 1];
            for (int i = 1; i < startAt.size(); i++) {
                v[i - 1] = _getArg_(startAt, i);
            }
            BigInteger old_r;
            BigInteger r;
            do {
                old_r = number.get();
                r = old_r;
                for (int i = 0; i < v.length; i++)
                    r = r.divide(v[i]);
            }
            while (!number.compareAndSet(old_r, r));
        }
        catch (ArithmeticException ex) {
            // prévoir la gestion de l'exception division par zéro sur exception seulement.
            // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
            if (ex.getMessage().equals("Division by zero")) {
                throw new InterpreterException(StdErrors.Division_by_zero);
            }
            else {
                throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
            }
        }
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&/!
     *
     * Note: S'il n'y à pas d'argument, la méthode effectue de l'opération 1/n (n étant la valeur courante).
     *
     * Les types d'entrées supportées sont : number, string, Integer et Decimal.
     *
     * @param startAt
     * @return
     * @throws Exception
     */
    public Node external_mutator_fetch_and_div(Node startAt) throws Exception {
        /*
         * s'il n'y a pas d'arguments, on considère qu'il s'agit de l'expression (- n)...
         */
        SELF.require_SELF_mutable();
        int asize = startAt.size();
        if (asize == 1) {
            BigInteger d = BigInteger.ONE;
            try {
                BigInteger old_r;
                BigInteger r;
                do {
                    old_r = number.get();
                    r = d.divide(old_r);
                }
                while (!number.compareAndSet(old_r, r));
                return Node.createExternal(new External_Integer(old_r));
            }
            catch (ArithmeticException ex) {
                // prévoir la gestion de l'exception division par zéro sur exception seulement.
                // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
                if (ex.getMessage().equals("Division by zero")) {
                    throw new InterpreterException(StdErrors.Division_by_zero);
                }
                else {
                    throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
                }
            }

        }
        /*
         * s'il y a au moins un argument, on considère la forme (- n [args...])...
         */
        try {
            BigInteger[] v = new BigInteger[startAt.size() - 1];
            for (int i = 1; i < startAt.size(); i++) {
                v[i - 1] = _getArg_(startAt, i);
            }
            BigInteger old_r;
            BigInteger r;
            do {
                old_r = number.get();
                r = old_r;
                for (int i = 0; i < v.length; i++)
                    r = r.divide(v[i]);
            }
            while (!number.compareAndSet(old_r, r));
            return Node.createExternal(new External_Integer(old_r));
        }
        catch (ArithmeticException ex) {
            // prévoir la gestion de l'exception division par zéro sur exception seulement.
            // c'est plus rapide car on n'a pas besoin de tester la valeur à chaque fois.
            if (ex.getMessage().equals("Division by zero")) {
                throw new InterpreterException(StdErrors.Division_by_zero);
            }
            else {
                throw new InterpreterException(StdErrors.extend(StdErrors.Arithmetic_error, ex.getMessage()));
            }
        }
    }


    /**
     * Retourne l'opération AND de l'Integer courant par la liste des valeurs posées en arguments.
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_and(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        int i = 1;
        int asize = startAt.size();
        while (i < asize && r.signum() != 0)
            r = r.and(_getArg_lazy_(startAt, i++));
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * Réalise statiquement l'opération AND de l'Integer courant par la liste des valeurs posées en arguments.
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_and(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            int i = 0;
            while (i < v.length && r.signum() != 0)
                r = r.and(v[i++]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&and!
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode supporte également les arguments lazy (dont l'évaluation est paresseuse).
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_and(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            int i = 0;
            while (i < v.length && r.signum() != 0)
                r = r.and(v[i++]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne l'opération OR de l'Integer courant par la liste des valeurs posées en arguments.
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode NE SUPPORTE PAS les arguments lazy. Les grands nombres entiers n'ayant pas de limite de bits,
     * l'opération OR ne peut s'arrêter sur un résultat fini avant l'évaluation complète de tous les arguments.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_or(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        int i = 1;
        int asize = startAt.size();
        while (i < asize && r.signum() != 0)
            r = r.or(_getArg_(startAt, i++));
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur or!
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode NE SUPPORTE PAS les arguments lazy. Les grands nombres entiers n'ayant pas de limite de bits,
     * l'opération OR ne peut s'arrêter sur un résultat fini avant l'évaluation complète de tous les arguments.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_or(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.or(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&or!
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     * La méthode NE SUPPORTE PAS les arguments lazy. Les grands nombres entiers n'ayant pas de limite de bits,
     * l'opération OR ne peut s'arrêter sur un résultat fini avant l'évaluation complète de tous les arguments.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_or(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = r.or(v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne l'opération XOR de l'Integer courant par la liste des valeurs posées en arguments.
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_xor(Node startAt) throws Exception {
        startAt.isGoodArgsLength(false, 2);
        BigInteger r = number.get();
        int i = 1;
        int asize = startAt.size();
        while (i < asize)
            r = BigIntegerMath.xor(r, _getArg_(startAt, i++));
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur xor!
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_xor(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = BigIntegerMath.xor(r, v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&xor!
     *
     * Attention: Les arguments supportés sont convertis en Integer pour pouvoir s'appliquer à une opération bit à bit.
     * =========  Ceci contraste avec l'opération (and number ...) qui accepte aussi des TRUE-équivalents...
     *
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_xor(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsLength(false, 2);
        BigInteger[] v = new BigInteger[startAt.size() - 1];
        for (int i = 1; i < startAt.size(); i++) {
            v[i - 1] = _getArg_(startAt, i);
        }
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r;
            for (int i = 0; i < v.length; i++)
                r = BigIntegerMath.xor(r, v[i]);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }


    /**
     * Retourne l'opération SHIFT-L de l'Integer courant par le number (int) fourni.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_lshift(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        BigInteger r = number.get();
        r = r.shiftLeft((int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber());
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur lshift!
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_lshift(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(2);
        int bits = (int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber();
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.shiftLeft(bits);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&lshift!
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_lshift(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(2);
        int bits = (int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber();
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.shiftLeft(bits);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Retourne l'opération SHIFT-R de l'Integer courant par le number (int) fourni.
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_rshift(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(2);
        BigInteger r = number.get();
        r = r.shiftRight((int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber());
        return Node.createExternal(new External_Integer(r));
    }

    /**
     * surcharge de l'opérateur rshift!
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_rshift(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(2);
        int bits = (int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber();
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.shiftRight(bits);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&rshift!
     *
     * @param startAt
     * @return Node:Integer
     * @throws Exception
     */
    public Node external_mutator_fetch_and_rshift(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(2);
        int bits = (int) startAt.getSubNode(1, Node.TYPE_NUMBER).getNumber();
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.shiftRight(bits);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * retourne le résultat de l'opération NOT.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_not(Node startAt) throws Exception {
        startAt.isGoodArgsCnt(1);
        return Node.createExternal(new External_Integer(number.get().not()));
    }

    /**
     * Opération NOT statique + atomique.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_not(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.not();
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&not!
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_fetch_and_not(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.not();
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Opération incrémentation statique et atomique.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_incr(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.add(BigInteger.ONE);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * surcharge de l'opérateur fetch&incr!
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_fetch_and_incr(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.add(BigInteger.ONE);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /**
     * Opération decrémentation statique et atomique.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_decr(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.subtract(BigInteger.ONE);
        }
        while (!number.compareAndSet(old_r, r));
        return null;
    }

    /**
     * Opération decrémentation statique et atomique.
     *
     * @param startAt
     * @return Node:number
     * @throws Exception
     */
    public Node external_mutator_fetch_and_decr(Node startAt) throws Exception {
        SELF.require_SELF_mutable();
        startAt.isGoodArgsCnt(1);
        BigInteger old_r;
        BigInteger r;
        do {
            old_r = number.get();
            r = old_r.subtract(BigInteger.ONE);
        }
        while (!number.compareAndSet(old_r, r));
        return Node.createExternal(new External_Integer(old_r));
    }

    /*
     * ----------------------------------------------------------------------------
     *
     * Optimisation par cache d'instanciantion (mars 2012) rev 1.0-6321.0
     *
     * ----------------------------------------------------------------------------
     */


    private static ORef _optim_symbols_cache_ = new ORef();

    @Override
    public Object getSymbolsCache() {
        return _optim_symbols_cache_.getRef();
    }

    @Override
    public void setSymbolsCache(Object cache) {
        _optim_symbols_cache_.setRef(cache);
    }

    public void setNumber(BigInteger number) {
        this.number.getAndSet(number);
    }

    public BigInteger getNumber() {
        return number.get();
    }

}
TOP

Related Classes of abstrasy.libraries.math.External_Integer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.