Fast Navision Bit XOR

rdebathrdebath Member Posts: 383
I'm looking for a fast way to do a binary XOR on 32 bit integers in Navision.
So far I have something that works; but only if "faster than a snail" isn't on the requirements.

I tried a COM object and yes it's quite a bit quicker in the Classic client but it makes the RTC slower than the unmodified Classic client (it's normally about 10 times faster for this.) Plus the hassle of actually having to install it of course.

The feeling of the code below is "is a bit slow" even on the RTC at the moment; on the Classic client it's: "looks like it's crashed".
So any bright ideas ?
PROCEDURE BitXOR@1000000014(A@1000000000 : Integer;B@1000000001 : Integer) : Integer;
    VAR
      Pos@1000000002 : Integer;
      Tmp@1000000003 : Integer;
      i@1000000004 : Integer;
      ANeg@1000000006 : Boolean;
      BNeg@1000000007 : Boolean;
    BEGIN
      Pos := 1;
      Tmp := 0;

      IF A < 0 THEN BEGIN
        ANeg := TRUE;
        A := A - -2147483648;
      END;

      IF B < 0 THEN BEGIN
        BNeg := TRUE;
        B := B - -2147483648;
      END;

      FOR i := 1 TO 30 DO BEGIN
        IF (A MOD 2) <> (B MOD 2) THEN
          Tmp += Pos;
        Pos *= 2;
        A := A DIV 2;
        B := B DIV 2;
      END;

      // Bit31
      IF (A MOD 2) <> (B MOD 2) THEN
        Tmp += Pos;

      // Bit32
      IF ANeg XOR BNeg THEN
        Tmp := Tmp - 1073741824 - 1073741824;
      EXIT(Tmp);
    END;

Comments

  • kinekine Member Posts: 12,562
    I think that there is no quicker method how to calc xor for signed integer. Of course you can try to call automation e.g. for scripting t calc the result... but I wonder why "looks like it's crashed" on classic... Isn't there another problem somewhere else?
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • rdebathrdebath Member Posts: 383
    kine wrote:
    ... but I wonder why "looks like it's crashed" on classic... Isn't there another problem somewhere else?

    It looks like it crashed because I'm doing around a hundred thousand XORs, this takes time ... lots of time ...

    I thought I'd found an answer using a COM object but the RTC must take of the order of a quarter of a millisecond to make a single call to a COM object; that mounts up quickly too.

    I suppose I'm going to have to shift more code into the COM object, of course that means piping a BLOB through the COM object too. Oh hum, I'll wait a little while before I dig out the VB6 compiler again.
  • kinekine Member Posts: 12,562
    Question is, why you need to do xor in NAV... :-)
    Kamil Sacek
    MVP - Dynamics NAV
    My BLOG
    NAVERTICA a.s.
  • David_SingletonDavid_Singleton Member Posts: 5,479
    kine wrote:
    Question is, why you need to do xor in NAV... :-)

    The only time I ever needed to was to write a game. :whistle:
    David Singleton
  • rdebathrdebath Member Posts: 383
    :-$ It's for the gov'ment.

    Just a little bit of SHA1 with some blowfish flavouring. :mrgreen:
  • kitikkitik Member Posts: 230
    After 5 year developing in Navision, today I needed to use a XOR for the first time.

    In a request form, I had 6 textcontrols (grouped in pairs) that I wanted to make editable/uneditable under some conditions. One, and only one, of the pairs should be editable at the time.

    I decided to create a procedure, to call it when needed. I wanted to be sure that only one of the bool parameters where set to TRUE.
    Here you have the code that helped me implement my own XOR condition:
    SetEditableControls(Boolean1,Boolean2,Boolean3)
    IF Boolean1 THEN
      XORcount += 1;
    IF Boolean2 THEN
      XORcount += 1;
    IF Boolean3 THEN
      XORcount += 1;
    
    IF XORcount <> 1   THEN
      ERROR(Txt005);
    [..]
    

    Salut!
    Laura Nicolàs
    Author of the book Implementing Dynamics NAV 2013
    Cursos Dynamics NAV (spanish) : http://clipdynamics.com/ - A new lesson released every day.
  • rmv_RUrmv_RU Member Posts: 119
    Some logical functions:
    BitOR(lInt1 : BigInteger;lInt2 : BigInteger) retVal : BigInteger
    //rmv_090210_$10547+
    lPos :=1;
    retVal := 0;
    lMaxBit := 32;
    FOR i:=1 TO lMaxBit DO BEGIN
      IF ((lInt1 MOD 2) =1) OR ((lInt2 MOD 2)=1) THEN
        retVal := retVal + lPos;
      lPos := lPos * 2;
      lInt1 :=  lInt1 DIV 2;
      lInt2 :=  lInt2 DIV 2;
    END;
    
    BitAND(lInt1 : BigInteger;lInt2 : BigInteger) retVal : BigInteger
    //rmv_090210_$10547+
    lPos :=1;
    retVal := 0;
    lMaxBit := 32;
    FOR i:=1 TO lMaxBit DO BEGIN
      IF ((lInt1 MOD 2) =1) AND ((lInt2 MOD 2)=1) THEN
        retVal := retVal + lPos;
      lPos := lPos * 2;
      lInt1 :=  lInt1 DIV 2;
      lInt2 :=  lInt2 DIV 2;
    END;
    
    BitXOR(lInt1 : BigInteger;lInt2 : BigInteger) retVal : BigInteger
    //rmv_090210_$10547+
    lPos :=1;
    retVal := 0;
    lMaxBit := 32;
    FOR i:=1 TO lMaxBit DO BEGIN
      IF ((lInt1 MOD 2) +  (lInt2 MOD 2))=1 THEN
        retVal := retVal + lPos;
      lPos := lPos * 2;
      lInt1 :=  lInt1 DIV 2;
      lInt2 :=  lInt2 DIV 2;
    END;
    
    Looking for part-time work.
    Nav, T-SQL.
  • SogSog Member Posts: 1,023
    just a FYI, but after reviewing code in NAV5 you have a native XOR namely "XOR"
    I found it in the GetCaptionClass on form 403 (Purch. Order Statistics)
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • kitikkitik Member Posts: 230
    Thanks Sog,

    I did not found any reference to XOR in the help, so I thought it didn't exist as a command.
    I changed my code, now it looks like this
    IF NOT (Boolean1 XOR Boolean2 XOR Boolean3) THEN
      ERROR(Txt005);
    
    Salut!
    Laura Nicolàs
    Author of the book Implementing Dynamics NAV 2013
    Cursos Dynamics NAV (spanish) : http://clipdynamics.com/ - A new lesson released every day.
  • rdebathrdebath Member Posts: 383
    kitik wrote:
    Thanks Sog,

    I did not found any reference to XOR in the help, so I thought it didn't exist as a command.
    I changed my code, now it looks like this
    IF NOT (Boolean1 XOR Boolean2 XOR Boolean3) THEN
      ERROR(Txt005);
    
    Salut!

    More FYI, that operator has been present since the early days, eg: version 2 or earlier. It only works on booleans though so is logically equivalent to the "<>" operator which makes it useless as "<>" is normally considered a lot more obvious.
  • IsakssonMiIsakssonMi Member Posts: 77
    Here are some bitwise operations, the main methods depend on the helper methods (I can't tell if they are fast or not):
    ComputeXor(num1 : Integer;num2 : Integer) : Integer
    /// <summary>
    /// Returns Logical XOR value from two integers
    /// </summary>
    /// <arguments>
    ///   <arguement name="num1" datatype="Integer" />
    ///   <arguement name="num2" datatype="Integer" />
    /// </arguments>
    /// <variables>
    ///   <variable name="parsers" dimensions="2" datatype="Text1024" />
    ///   <variable name="i" datatype="Integer" />
    ///   <variable name="result" datatype="Text1024" />
    ///   <variable name="max" datatype="Integer" />
    /// </variables>
    /// <return_value datatype="Integer" />
    
    parsers[1] := IntToBinary(num1);
    parsers[2] := IntToBinary(num2);
    
    IF (STRLEN(parsers[1]) > STRLEN(parsers[2])) THEN
      max := STRLEN(parsers[1])
    ELSE
      max := STRLEN(parsers[2]);
    
    FOR i:=max DOWNTO 1 DO
      result += FORMAT(NOT (Right(parsers[1], i) = Right(parsers[2], i)), 0, '<Number>');
    EXIT(BinaryToInt(result));
    
    ComputeAnd(num1 : Integer;num2 : Integer) : Integer
    /// <summary>
    /// Returns Logical AND value from two integers
    /// </summary>
    /// <arguments>
    ///   <arguement name="num1" datatype="Integer" />
    ///   <arguement name="num2" datatype="Integer" />
    /// </arguments>
    /// <variables>
    ///   <variable name="parsers" dimensions="2" datatype="Text1024" />
    ///   <variable name="i" datatype="Integer" />
    ///   <variable name="result" datatype="Text1024" />
    ///   <variable name="max" datatype="Integer" />
    /// </variables>
    /// <return_value datatype="Integer" />
    parsers[1] := IntToBinary(num1);
    parsers[2] := IntToBinary(num2);
    
    IF (STRLEN(parsers[1]) > STRLEN(parsers[2])) THEN
      max := STRLEN(parsers[1])
    ELSE
      max := STRLEN(parsers[2]);
    
    FOR i:=max DOWNTO 1 DO
      result += FORMAT((Right(parsers[1], i) = '1') AND (Right(parsers[2], i) = '1'), 0, '<Number>');
    EXIT(BinaryToInt(result));
    
    ComputeNot(num1 : Integer;num2 : Integer) : Integer
    /// <summary>
    /// Returns Logical NOT value from two integers
    /// </summary>
    /// <arguments>
    ///   <arguement name="num1" datatype="Integer" />
    ///   <arguement name="num2" datatype="Integer" />
    /// </arguments>
    /// <variables>
    ///   <variable name="parsers" dimensions="2" datatype="Text1024" />
    ///   <variable name="i" datatype="Integer" />
    ///   <variable name="result" datatype="Text1024" />
    ///   <variable name="max" datatype="Integer" />
    /// </variables>
    /// <return_value datatype="Integer" />
    parsers[1] := IntToBinary(num1);
    parsers[2] := IntToBinary(num2);
    
    IF (STRLEN(parsers[1]) > STRLEN(parsers[2])) THEN
      max := STRLEN(parsers[1])
    ELSE
      max := STRLEN(parsers[2]);
    
    FOR i:=max DOWNTO 1 DO
      result += FORMAT(Right(parsers[1], i) = Right(parsers[2], i), 0, '<Number>');
    EXIT(BinaryToInt(result));
    
    ComputeOr(num1 : Integer;num2 : Integer) : Integer
    /// <summary>
    /// Returns Logical OR value from two integers
    /// </summary>
    /// <arguments>
    ///   <arguement name="num1" datatype="Integer" />
    ///   <arguement name="num2" datatype="Integer" />
    /// </arguments>
    /// <variables>
    ///   <variable name="parsers" dimensions="2" datatype="Text1024" />
    ///   <variable name="i" datatype="Integer" />
    ///   <variable name="result" datatype="Text1024" />
    ///   <variable name="max" datatype="Integer" />
    /// </variables>
    /// <return_value datatype="Integer" />
    parsers[1] := IntToBinary(num1);
    parsers[2] := IntToBinary(num2);
    
    IF (STRLEN(parsers[1]) > STRLEN(parsers[2])) THEN
      max := STRLEN(parsers[1])
    ELSE
      max := STRLEN(parsers[2]);
    
    FOR i:=max DOWNTO 1 DO
      result += FORMAT(NOT ((Right(parsers[1], i) = '0') AND (Right(parsers[2], i) = '0')), 0, '<Number>');
    EXIT(BinaryToInt(result));
    
    BinaryToInt(value : Text[1024]) result : BigInteger
    /// <summary>
    /// Returns Integer value from a binary string
    /// </summary>
    /// <arguments>
    ///   <arguement name="value" datatype="Text1024" />
    /// </arguments>
    /// <variables>
    ///   <variable name="multiplier" datatype="BigInteger" />
    ///   <variable name="converted" datatype="Integer" />
    ///   <variable name="buffer" datatype="Integer" />
    ///   <variable name="i" datatype="Integer" />
    /// </variables>
    /// <return_value name="result" datatype="BigInteger" />
    multiplier := 1;
    FOR i := STRLEN(value) DOWNTO 1 DO BEGIN
      EVALUATE(buffer, COPYSTR(value, i, 1));
      result     += buffer * multiplier;
      multiplier *= 2;
    END;
    
    IntToBinary(value : BigInteger) result : Text[1024]
    /// <summary>
    /// Returns Binary string value from an Integer
    /// </summary>
    /// <arguments>
    ///   <arguement name="value" datatype="BigInteger" />
    /// </arguments>
    /// <return_value name="result" datatype="Text1024" />
    WHILE(value >= 1) DO BEGIN
      result  := FORMAT(value MOD 2) + result;
      value   := value DIV 2;
    END;
    
    Right(value : Text[1024];pos : Integer) : Text[1]
    /// <summary>
    /// Returns right string value by position
    /// </summary>
    /// <arguments>
    ///   <arguement name="value" datatype="Text1024" />
    ///   <arguement name="pos" datatype="Integer" />
    /// </arguments>
    /// <return_value datatype="Text1" />
    IF pos > STRLEN(value) THEN
      EXIT('0');
    EXIT(COPYSTR(value, STRLEN(value) - pos + 1, 1));
    
  • rdebathrdebath Member Posts: 383
    IsakssonMi wrote:
    Here are some bitwise operations, the main methods depend on the helper methods (I can't tell if they are fast or not):
    The speed is less than a tenth that of the code in my first message, and the results apparently aren't correct.

    It looks like you're not taking note of negative numbers properly, an XOR of 0 and -1 should be -1, your result is 0.
Sign In or Register to comment.