bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: expression evaluation problem


From: L A Walsh
Subject: Re: expression evaluation problem
Date: Thu, 25 Jul 2019 10:29:08 -0700
User-agent: Thunderbird


On 2019/07/24 11:49, Greg Wooledge wrote:
> On Wed, Jul 24, 2019 at 11:43:11AM -0700, L A Walsh wrote:
>   
>> Those aren't my variables.
>> If you assign the integer attribute to a variable it isn't the same
>> as when you don't.
>>     
>
> In this case it *is*, because everything is being fed to an arithmetic
> command anyway.
>
> Simplifying the bug report as much as possible lets us avoid
> confusing and unnecessary diversions.
>   
It might, but also can make the example less instructive and less
general.  As the double paren's change the output, maybe I should use
quotes again:

str='cf80' v=960  uxtra=1 c=0
v="$v|($uxtra>=++$c?((0x${str:2*$c:2})&63)<<(6*($uxtra-$c)):0)"
echo $v
960|(1>=++0?((0xcf)&63)<<(6*(1-0)):0)

If I put back the original definitions of everything but 'str' being
and integer and then try it with the quotes:

str='cf80' int v=960 uxtra=1 c=0
v="$v|($uxtra>=++$c?((0x${str:2*$c:2})&63)<<(6*($uxtra-$c)):0)"
echo $v
960

So leaving the integer attributes and putting the whole right side
in might be a way to avoid bash reordering expression evaluation (?).

>   
>>> The ${str:2*c:2} part is performed first, while c is still 0, and yet it 
>>> expands to "cf".      
>> ---
>>     Why?  It isn't even necessary when 'c' is greater than 'uxtra'
>>     
>
> Because that's how bash works.
>   
----
    That doesn't explain why.


>               $((expression))
>
>        The expression is treated as if it were within  double  quotes,
---
I didn't use $((...)), I'd put the whole thing in ((...)) which I hoped
would treat the whole expression consistently.



>> Have you considered performing your calculation in steps, with
>> intermediate values stored in temporary variables with clear names?
>> That greatly improves readability.
>>     
---
    I compared my final form with one that was broken into intermediate
steps:

My core calculation (in 1 step -- not ideal for maintenance, but it was
a proof of concept for me):

  (( (v=(v & byte_masks[uxtra]) << 6*uxtra
  | (uxtra>=++c ? (63&sv[c]) << 6*(uxtra-c)
    | (uxtra>=++c ? (63&sv[c]) << 6*(uxtra-c)
      | (uxtra>=++c ? (63&sv[c]) << 6*(uxtra-c)
        | (uxtra>=++c ? (63&sv[c]) << 6*(uxtra-c)
          | (uxtra>=++c ? (63&sv[c]) << 6*(uxtra-c)
                        : 0 )
                      : 0 )
                    : 0 )
                  : 0 )
              : 0 )
              )
            ))
----
The one broken into steps looked like:

  int s1=0 s2=0 s3=0 s4=0 s5=0 s6=0

  int s1=$(($v & byte_masks[uxtra] << 6*uxtra))
  c+=1
  if ((uxtra>=c)); then
    m2=$(((63&sv[c])))
    s2=$((m2 << 6*(uxtra-c)))
    c+=1
    if ((uxtra>=c)); then
      m3=$(((63&sv[c])))
      s3=$((m2 << 6*(uxtra-c)))
      c+=1
      if ((uxtra>=c)); then
        m4=$(((63&sv[c])))
        s4=$((m2 << 6*(uxtra-c)))
        s4=$(((63&sv[c]) << 6*(uxtra-c)))
        c+=1
        if ((uxtra>=c)); then
          m5=$(((63&sv[c])))
          s5=$((m2 << 6*(uxtra-c)))
          c+=1
          if ((uxtra>=c)); then
            m6=$(((63&sv[c])))
            s6=$((m2 << 6*(uxtra-c)))
          fi
        fi
      fi
    fi
  fi
  v=$((s1|s2|s3|s4|s5|s6))

----
    I know it did expand the variable names, but I wanted to get
a quick idea of timing differences/overhead.
Timing it to decode a 4-hex numbers showed the split form
to take a bit over 25% longer.

>
>> Isolating the ++c into its own step would also remove all questions
>> about whether the increment is performed before or after other
>> calculations (or in this case, parameter expansions).  In-lining ++c
>> inside a larger calculation can be OK in very simple situations, but
>> a nightmare to read/understand/debug in more complex cases.
>>     

I've had programs like the 1st one above, where to debug it I rewrote it
into an if/then/else structure for debugging.  Since it wasn't a time
critical routine, I just kept it in the expanded form as it was (is) easier
to maintain and modify.

Note while you removed the 'int' attribute on the vars, the working
form needed them to produce a correct result.

To fix the code, I changed the string into an array which seems
to get computed in expected order".



reply via email to

[Prev in Thread] Current Thread [Next in Thread]