在bash中解决(简单)数值练习

时间:2015-03-24 19:50:39

标签: bash math

你们中的一些人可能对Project Euler很熟悉,而且我现在正在尝试他们的一些问题来教给自己更多的bash。他们比's-script&y;'但它有助于语法等。

问题目前要求我解决:

  

如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.

     

查找低于1000的3或5的所有倍数的总和。

我的代码如下:

#!/bin/bash

i="1"

for i in `seq 1 333`
do
    threes[$i]=`calc $i*3` # where 'calc' is a function written in bashrc
    #calc actually looks like: calc() {awk "BEGIN { print "$*"} }

    let "sumthrees = sumthrees + ${threes[$i]}"
done

for i in `seq 1 199`
do
    fives[$i]=`calc $i*5`
    let "sumfives = sumfives + ${fives[$i]}"
done

let "ans = $sumfives + $sumthrees"

echo "The sum of all 3 factors is $sumthrees and the sum of all five factors is $sumfives"
echo "The sum of both is $ans"

#So I can repeatedly run the script without bash remembering the variables between executions
unset i
unset fives
unset threes
unset sumfives
unset sumthrees
unset ans

到目前为止,我还没有得到正确答案,但对于我出错的地方已经没有了。 (仅供参考,剧本目前给我266333,我相信这很接近,但我还不知道答案。)

任何人都能看到任何东西吗?而对于我自己的学习,如果有更优雅的解决方案,人们可​​能愿意分享这将是伟大的。

修改

感谢所有的答案,超级翔实。由于这里有很多有用的答案,我接受我最喜欢的答案作为正确的答案。

5 个答案:

答案 0 :(得分:3)

  • 蓝月亮指出了你逻辑的实际问题。

  • 您不需要将所有三和五个存储在数组中,因为您以后不需要它们。

  • 如果您使用./yourscriptbash script,则无需在脚本末尾取消设置变量,因为它们会随着 shell实例(最好在任何情况下首先初始化它们。)

  • 您不需要awk来做数学,bash就可以了。

  • seqlet不是在bash脚本中执行任何操作的最佳方式。

这是一个直截了当的版本:

#!/bin/bash
sum=0
for ((i=1; i<1000; i++))
do
  if (( i%3 == 0 || i%5 == 0 ))
  then
    (( sum += i ))
  fi
done
echo "$sum"

答案 1 :(得分:2)

你的逻辑几乎是正确的,除了有数字除以 3 5.所以你要将这些数字加两次。因此,你的回答是错误的。

使用另一个类似于你的循环,并从结果中减去除以3和5的循环。

答案 2 :(得分:2)

您可能会发现一些有用的提示:

在bash中,您使用let为shell提供一个变量应该被视为数字的提示。所有bash变量都是字符串,但您可以对数字字符串进行算术运算。如果我说let i=1,那么我将设置为1,但如果我说let i="taco",那么$i将为0,因为它无法读取为数字。在shell中进行数学工作时,您可以实现少量的类型安全性。

Bash还有$((this))数学机制!您可以自行查看:echo $((2 + 2)) - &gt; 4,与此问题更相关:echo $((6 % 3 == 0)) - &gt; 1

如果您不熟悉,%将第一个数字除以第二个数字,并返回余数;当余数为0时,意味着第一个是可分割的第二个! ==是测试两个事物是否相等的测试,对于像这样的逻辑测试,1代表true,0代表false。所以我正在测试6是否可以被3整除,它是,并且我得到的值是1。

测试括号[ ... ]有一个“test for equality”标志-eq,您可以使用它来检查数学表达式是否具有某个值(man test for more details)!< / p>

$ let i=6
$ echo $((i % 3 == 0 || i % 5 == 0))
1
$ if [ $((i % 3 == 0 || i % 5 == 0)) -eq 1 ]; then echo "yes"; fi
yes

||是另一个逻辑测试 - 当a为真 b为真时,$((a || b))将为1(真)。

最后,不是为数字6执行此操作,而是可以在for循环中执行此操作,并在每次找到3或5的倍数时递增sum变量:

let sum=0
for i in {1..1000}; do
    if [ $((i % 3 == 0 || i % 5 == 0)) -eq 1 ]; then
        let sum=$((sum + i))
    fi
done
echo $sum

你有一个可行的解决方案!

Bash有很多不错的小技巧(而且更多的意思是丑陋的技巧),但至少要学习它们中的一小部分才能将它作为脚本工具使用。

答案 3 :(得分:2)

如何创造性地使用模数函数&amp;一些检查。然后你只有一个循环。

#!/bin/bash

i=1

while [ $i -lt 1000 ]
do 
    if [ $(($i % 3)) -eq 0 ] || [ $(($i % 5)) -eq 0 ]
        then
            sumall=$(($sumall+$i))
    fi
    i=$(($i+1))
done

echo "The sum of both is $sumall"

答案:233168

答案 4 :(得分:1)

另一种解决方案:

#!/bin/bash

sum=0
for n in {1..999}; do [ $(((n%5) * (n%3))) -eq 0 ] && sum=$((sum+n)); done
echo $sum

脚本循环遍历1000以下的所有数字,测试数字mod 3和数字mod 5的乘积是否为0(如果其中一个数字为零,则两个数字的乘积只能为零)。如果是这种情况,它会将当前数字添加到一个总和中,然后打印出来。

顺便说一下,如果我是你,我会在脚本中包含calc函数的定义,以获得一个不需要你特定配置的独立解决方案。