help-bash
[Top][All Lists]
Advanced

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

Re: let vs double-parentheses


From: Koichi Murase
Subject: Re: let vs double-parentheses
Date: Sun, 7 Mar 2021 11:45:21 +0800

2021年3月7日(日) 10:23 Lawrence Velázquez <vq@larryv.me>:
> > On Mar 6, 2021, at 8:28 PM, Peng Yu <pengyu.ut@gmail.com> wrote:
> > I was not aware of this syntax `a+={1..100000}`.
>
> It's just normal brace expansion.
>
> bash-5.1$ echo let a=0 a+={1..5}
> let a=0 a+=1 a+=2 a+=3 a+=4 a+=5

Yes, it's not special syntax. Actually, we can also use the brace
expansions in `((...))', but `((a+={1..5}))' will be expanded as

  ((a+=1 a+=2 a+=3 a+=4 a+=5))

so will cause a syntax error [the same as in the first example `((a=1
b=2 c=3))']. But... now I noticed that one could write

  ((+0,a+={1..5},1))

so that it will be expanded as

  ((+0,a+=1,1 +0,a+=2,1 +0,a+=3,1 +0,a+=4,1 +0,a+=5,1))

But, it's tricky and not intuitive. It's also not as flexible as
`let', e.g., it will be more tricky to include `a=0' in the same
command.

> > Is there any other
> > syntax that could have better performance as well?

If you are asking some tricks related to the arithmetic expressions,
you may consider the use of the conditional operator
`cond?expr1:expr2'? Usually

  ((i%10==0?(a+=i):(b+=i)))

will be faster than

  if ((i%==10==0)); then ((a+=i)); else ((b+=i)); fi

But if the expressions in the discarded branches become long, the
latter will be faster. In this case, one may store the long expression
in a variable:

  RareCase='some_long_arithmetic_expression'
  ((i%10==0?RareCase:(b+=i)))

Instead, one can use a table of expressions:

  table=([1]='a+=i' [0]='b+=i')
  ((table[i%10==0]))

This method is not restricted to binary branching but can also be used
as a kind of a jump table. For example,

  if ((i==1)); then ((a=2021)); elif ((i==2)); then ((a=3)); elif
((i==3)); then ((a=7)); fi

can be written as

  table=([1]='a=2021' [2]='a=3' [3]='a=7')
  ((table[i]))

which is much faster than ``if-else chain'' or ``?: chain''
particularly when the number of branches are large and each branch
contains long arithmetic expressions.

https://github.com/akinomyoga/ble.sh/blob/aae553cb/src/decode.sh#L3836-L3867
is an example of a UTF-8 decoder with this trick which I believe much
faster than a naive implementation in pure Bash. Actually, if it is
possible, I would like to further optimize this UTF-8 decoder. Does
anyone have any idea to optimize this decoder?

> This particular trick of syntax is not very compelling, as the
> closed-form expression is simple.
> bash-5.1$ time (( r=1, s=100000, a=(s-r+1)*(r+s)/2 ))

The above code `let a=0 a+={1..100}' was just an example for the
explanation. This trick can be used for a wider class of operations
that don't necessarily have obvious  ``closed forms''. For example
(though it's again a simple example),

let i={1..1000..2},'a[i]=i*i'

But I think the important point is that `let a+={1..5}' is shorter,
intuitive, and easier to write, so there are some cases that the
combination of let and brace expansions are more useful, in
particular, in interactive uses. (I wouldn't say this trick is always
better than for loops. It's case-by-case.)

--
Koichi



reply via email to

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