Find the index of a number in the fibonacci sequence - bash

I want to find the index of a number in the fibonacci sequence using recursion.
Example : 13 (my input) is the 8th (output) number of the fibonacci sequence
Here is my function :
#!/bin/bash
function fib() {
number=1
cpt=1
if [[ $number -lt $1 ]]
then
compteur=$(($cpt+ 1))
echo $(( $(fib $(($number - 1)) ) + $(fib $(($number - 2)) ) ))
fi
echo $cpt
}
fib $1
I have this error : Wrong symbol near the +
Then I don't know if my logic for the algorithm is good. I don't know if my syntax of how we are calling the function in the recursion in bash is great.
Any help would be appreciated. Thanks !

With recursion, would you please try the following:
#!/bin/bash
# "fib n" returns the nth Fibonacci number (n starts from 0)
fib() {
local n=$1
if (( n == 0 )); then
echo "0"
elif (( n == 1 )); then
echo "1"
else
echo "$(( $(fib "$(( n - 1 ))" ) + $(fib "$(( n - 2 ))" ) ))"
fi
}
input=$1 # user's input as a 1st argument to this script
for (( i = 0; ; i++ )); do # increment the index i starting from 0
f=$(fib i)
(( f >= input)) && break # if "fib i" >= input, then exit the loop
done
if (( f == input )); then # the input is a Fibonacci number
echo "$i"
else
echo "$i (input $input is not a Fibonacci number.)"
fi
By convention, the index starts with "0", then 13 is the 7th Fibonacci number.
Btw if you increase the input number, you'll see the execution of the script takes a while (e.g. please try with 987 as an input).
Here is an alternative without the recursion:
#!/bin/bash
f0=0
f1=1
input=$1
for (( i = 0; ; i++ )); do
(( f0 >= input )) && break
f2=$(( f1 + f0 ))
f0=$f1
f1=$f2
done
if (( f0 == input )); then
echo "$i"
else
echo "$i (input $input is not a Fibonacci number.)"
fi
Although the recursion is mathematically simple and elegant, the number
of computation depends on the implementation. Fibonacci sequence is a
typical example which requires a consideration.
The 1st script includes two problems:
In the 1st recursion, the fib function calls two fib functions.
In the 2nd recursion, four functions are called. The number of computation
reaches O(2**N).
The intermediate values such as fib(n-1) and fib(n-2) are discarded and
calculated again in the next invocation.

Related

newprime.sh: line 14: [: 0+1: integer expression expected

what's wrong with my code? I am trying to print prime numbers upto n digits
echo Enter Number
read num
for (( i=2; $i <= $num ; i++ ))
do
c=0
for (( j=2; $j <= $i ; j++))
do
mod=$(($i % $j))
if [ "$mod" -eq 0 ]
then
c=`expr $c+1`
fi
done
if [ "$c" -eq 1 ]
then
echo $c
fi
done
I don't have any idea what I'm doing wrong. If someone could tell me how to fix it I would be thankful
newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected
newprime.sh: line 14: [: 0+1+1+1: integer expression expected
newprime.sh: line 14: [: 0+1: integer expression expected
expr requires parameters to be passed as separate arguments. Quoting the POSIX standard for expr:
The application shall ensure that each of the expression operator symbols [...] and the symbols integer and string in the table are provided as separate arguments to expr.
The code here is appending all the operators into a single argument, hence your problem.
Thus:
c=$(expr "$c" + 1)
...NOT...
c=$(expr $c+1)
But don't do that at all. It's more efficient and more readable to write:
c=$(( c + 1 ))
Optimized with less iterations POSIX shell version:
#!/usr/bin/env sh
printf %s 'Enter Number: '
read -r num
i=1
while [ "$i" -le "$num" ]; do
c=0
j=2
# Stop checking division when divisor power 2 is greater than number
# or we identifed a divisor
while [ "$((j * j))" -le "$i" ] && [ "$c" -eq 0 ]; do
c=$((i % j == 0))
j=$((j + 1))
done
if [ "$c" -eq 0 ]; then
printf '%s\n' "$i"
fi
i=$((i + 2))
done
Or using a function:
#!/usr/bin/env sh
is_prime() {
j=2
# Check j is a divisor of argument number, while j^2 is less than number
while [ "$((j * j))" -le "$1" ]; do
# If j is a divisor of number before the end of the loop
# number is not prime, so return 1
[ "$(($1 % j))" -eq 0 ] && return 1
j=$((j + 1))
done
}
printf %s 'Enter Number: '
read -r num
i=1
while [ "$i" -le "$num" ]; do
if is_prime "$i"; then
printf '%s\n' "$i"
fi
i=$((i + 2))
done
Don't use expr. Put your mathematical expression inside (( )) (or echo $(( )) to print the result), and the shell will evaluate it.
See what the expr output looks like, vs regular shell arithmetic:
$ expr 0+1
0+1
$ echo "$((0+1))"
1
-eq with test, or single square brackets (eg [ 1 -eq 2 ]) prints an error if both operands aren't integers. That's what's causing your error.
Here's a fast and concise way to list primes in bash. You can put it in a function or script:
for ((i=2; i<="${1:?Maximum required}"; i++)); do
for ((j=2; j<i; j++)); do
((i%j)) || continue 2
done
echo "$i"
done
edit: Just to explain something, if (([expression])) evaluates to 0, it returns non-zero (1) (failure). If it evaluates to any other number (positive or negative), it returns zero (true). When a number divides evenly in to i, the modulo (%) (remainder) is zero. Hence the command fails, we know it's not prime, and we can continue the outer loop, for the next number.

Finding the greatest common divisor of two numbers in Bash

I am coding a program that computes the GCD of two numbers. My problem happens in some input cases:
GCD (88, 100) = 4
But my program returns an empty space (like it couldn't get the $gcd), but I haven't really got to the exact problem in my code yet.
#!/bin/bash
while true; do
read a b
gcd=$a
if [ $b -lt $gcd ]; then
gcd=$b
fi
while [ $gcd -ne 0 ]; do
x=`expr $a % $gcd`
y=`expr $b % $gcd`
if [ $x -eq 0 -a $y -eq 0 ]; then
echo "GCD ($a, $b) = $gcd"
break
fi
done
done
You could define a function that implements the Euclidean algorithm:
gcd() (
! (( $1 % $2 )) && echo $2 || gcd $2 $(( $1 % $2 ))
)
the function uses the ternary operator test && cmd1 || cmd2 and recursion (it calls itself). Or define a more readable version of the function:
gcd() (
if (( $1 % $2 == 0)); then
echo $2
else
gcd $2 $(( $1 % $2 ))
fi
)
Test:
$ gcd 88 100
4

Print Fibonacci series using recursion in bash with only 1 variable

I'd like to know how to print Fibonacci series using recursion in bash with only 1 variable.
From what I've done:
fib()
{
i=$1
if (( $i <= 1 ))
then echo 0
elif (( $i == 2 ))
then echo 1
else
echo $(( $(fib $(($i - 1)) ) + $(fib $(($i - 2)) ) ))
fi
}
echo $(fib $1)
I get the correct output of the final iteration, for example if I enter 10 I will get 34, but I'd like to print the whole sequence of numbers, i.e. all the iterations as well. How can I achieve that?
Another way I tried was by:
#!/bin/bash
arr[0]=0
arr[1]=1
for (( i=0; i<=10; i++ ))
do
echo -n "${arr[0]} "
arr[0]=$((${arr[0]} + ${arr[1]} ))
arr[1]=$((${arr[0]} - ${arr[1]} ))
done
echo ""
But obviously here I've used a for loop, but I don't want to use another variable.
Just for (my kind of) fun, this code prints the Fibonacci numbers from the 0th to the 92nd (as defined in Fibonacci number - Wikipedia) with a recursive function that uses no variables:
#! /bin/bash
function fib
{
echo ${3-0}
(($1 > 0)) && fib $(($1-1)) ${3-0} $((${2-1}+${3-0}))
}
fib 92
Some may claim that using the positional parameters ($1, $2, $3) for this is cheating, but then other solutions could be said to be using two variables ($i and $1).
The code takes under 0.01 seconds to run on my (oldish) Linux machine.
The code should work with numbers up to 92 with Bash version 3 or later on any platform. See Bash Number Limit?. Numbers higher than 93 will cause to code to produce garbage results due to arithmetic overflow.
Variables in bash are global by default. You need to make i local explicitly.
fib () {
local i
i=$1
if (( i <= 1 )); then
echo $i
else
echo $(( $(fib $((i-1)) ) + $(fib $((i - 2)) ) ))
fi
}
(Also, your base cases are a little off if you are starting with 0, and 2 need not be a base case; fib 2 can be derived from the base cases fib 0 and fib 1.)
If you want to print each fibonacci value from 1 to $n, I suggest:
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif (( i <= 1 )); then
echo $i
else
echo $(( $($FUNCNAME $((i - 1)) ) + $($FUNCNAME $((i - 2)) ) ))
fi
}
fib() {
local i
for (( i = 1; i <= $1; i++ )); do
fib_r $i
done
}
fib 10
outputs
0
1
1
2
3
5
8
13
21
34
It's still one variable, albeit one per function.
I use the bash variable $FUNCNAME in the recursive function so you don't have to hardcode the function name within itself. I got bit by not updating that line when I renamed the function.
Of course your performance will greatly improve if you cache the results: "fib 16" takes, on my VM, about 3.5 sec without caching and about 0.03 sec with caching.
fib_r() {
local i=$1
if (( i < 0 )); then
echo "Error: negative numbers not allowed" >&2
exit 1
elif [[ -n ${fib_cache[i]} ]]; then
echo "${fib_cache[i]}"
elif (( i <= 1 )); then
echo $i
else
echo $(( $( $FUNCNAME $((i - 1)) ) + $( $FUNCNAME $((i - 2)) ) ))
fi
}
fib_cache=()
fib() {
local i
for ((i=1; i<=$1; i++)); do
fib_cache[i]=$(fib_r $i)
echo "${fib_cache[i]}"
done
}

prime number function in shell script

I am new to Shell script. I have written a function to check weather a number is prime or not but I am getting error of Unary operator expected in if condition. Kindly point out where I have done mistake.
file :fprime.sh
prime ()
{
n=$1
t=0
for i in {2..$n}
do
r=`expr $n % $i`
if [ $r == 0 ]
then
t=`expr t + 1`
fi
done
if [ $t == 1 ]
then
echo "prime"
else
echo "not prime"
fi
}
prime
Output:
~$ ./fprime.sh 5
expr: syntax error
./fprime.sh: line 8: [: ==: unary operator expected
not prime
Try changing, 3 places there are other syntax error too,
1) if [ $r == 0 ]
// to
if [ $r -eq 0 ]
2) t=`expr t + 1`
// to
t=`expr $t + 1`
3) if [ $t == 1 ]
// to
if [ $t -eq 1 ]
Notes
1) and 3) , -eq is used to equate integers in bash == is to equate String/charactor(s)
2) - missed $ symbol for variable t
Also, just to point out, you can directly use the $1 without assigning to variable n again
The following function will return 0 (no error --> true) if the number is prime.
The function will return 1 (error --> false) if the number is not prime.
For those who never saw it before, REMAINDER_S is an array (in which every reminder of the division, different from zero, is stored).
As prime numbers are divisible only by themselves (and 1 of course), in the moment a division provides a reminder equals to zero, the number will not be prime.
Otherwise (none of the reminders is zero), the array REMINDER_S will be empty and the number will be a prime number.
Do not forget to use "break" in the first "if" statement, if you intend to substitute the "return 1" for some echo message.
is_prime () {
declare -a REMAINDER_S=()
let ARG_1=$1-1
for N in $(seq 2 $ARG_1)
do
let REMINDER=$1%$N
if [ $REMINDER == 0 ]
then
REMINDER_S=("${REMINDER_S[#]}" $REMINDER)
return 1
fi
done
if [ ${#REMINDER_S[#]} == 0 ]
then
return 0
fi
}
A simple code :
function prime()
{
for((i=2; i<=num; i++))
do
if [ `expr $num % $i` == 0 ]
then
echo $num is not prime
exit
fi
done
echo $num is a prime number
}
read num;
prime "$num";

What is this Bash Syntax in FizzBuzz Example

I just found the following FizzBuzz example on Hacker News and it uses a piece of syntax I'm finding it difficult to search for
for num in {1..100} ; do
out=""
(( $num % 3 == 0 )) && out="Fizz"
(( $num % 5 == 0 )) && out="${out}Buzz"
echo ${out:-$num}
done
The bit I don't understand is how the variable usage works in the echo line. Though I can obviously see that it becomes $out if not empty, else $num
for num in {1..100} ; do
Loop from 1 to 100.Set num to each integer on the way
out=""
Set out to nothing
(( $num % 3 == 0 )) && out="Fizz"
If the number is divisible by 3 set out to Fizz
(( $num % 5 == 0 )) && out="${out}Buzz"
If the number is divisible by 5 set out to whatever is contained in out then Buzz.
echo ${out:-$num}
Uses parameter substitution to check that out contains something, if it does not, then use num instead.
Echos result of the substitution.
done
Resources
http://tldp.org/LDP/abs/html/parameter-substitution.html - parameter substitution
http://tldp.org/LDP/abs/html/ops.html - let command ((...))
http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-7.html - loops

Resources