View Single Post
  #2   (View Single Post)  
Old 26th July 2019
IdOp's Avatar
IdOp IdOp is offline
Too dumb for a smartphone
 
Join Date: May 2008
Location: twisting on the daemon's fork(2)
Posts: 1,027
Default

Thank you for posting that, I enjoy playing with shell scripts for odd purposes.

Unfortunately, my knowledge of bc(1) is about zero, so naturally the first thing that came to my mind after looking at your script was "Hmmm, could you do that just with shell arithmetic and without bc ?" At first I thought it would be problematic, but after thinking about it a bit it seemed it would not be that difficult. So I had some fun writing a script to do it (shown below).

Here is my "analysis" which also explains how the script works. The script takes 3 arguments,

$1 = A = whole number of inches

$2 = B = numerator of fractional part

$3 = C = denominator of fractional part

So, "A B C" means A+B/C inches, which will be converted to cm with 4 digits precision, as an example. A and B must be non-negative integers, and C a positive integer. Then

( A + B/C ) inch = N * 10^{-4} cm

where N is a non-negative integer that we seek to find. A little algebra gives

[ ( AC + B) / C ] * 10^4 inch = N cm

Using inch = 2.54 cm this gives an answer for N:

N = [ ( AC + B ) / C ] * 10^2 * 254 = [ ( AC + B ) * 25400 ] / C

But, shell arithmetic is going to truncate this division, so to round it I think we should add C/2 to the top. I.e., if X is the [...] then replace it wtih X+C/2 = (2X+C)/2. Then the rounded value for N is

N = [ ( AC + B ) * 25400 * 2 + C ] / (2C)

Finally we want the integer and fractional parts of N * 10^{-4}. These are:

I = floor( N / 10^4 )

and (remainder times 10^4):

R = ( N - I * 10*4 )

The answer is basically "I.R" printed properly with printf().

Code:
#!/bin/sh

# Inches to CentiMeters (to 4 decimal precision)
# Arguments:  $1 = whole inches;  $2 = fractional numerator;  $3 = fractional denominator
#             i.e.,  $1 + $2 / $3 [inches]
#             Both $2 and $3 can be omitted together (for a whole inch)

# Argument checking is a bit rudimentary ...

if [ $# -eq 0  -o  $# -eq 2  -o  $# -ge 4 ]; then
    echo Error a.
    exit
fi

A=$1
B=${2:-0}
C=${3:-1}

if [ $C -le 0 ]; then
    echo Error b.
    exit
fi

N=$(( ( A * C + B ) * 25400 * 2 + C ))

N=$(( N / ( 2 * C ) ))

I=$(( N / 10000 ))

R=$((  N - I * 10000 ))

printf ">>  %d + %d / %d in  =  %d.%04d cm\n" $A $B $C $I $R
(To convert a whole number of inches, the script allows a single argument.)

Comments and corrections are welcome, as I haven't checked this extensively, but it seems to work in several cases I tried.

EDIT: There's a bug in the attached file. The printf statement should contain %04d as shown in the code block. Ooops. Hmmm, it seems the file didn't attach, just as well I guess! You can copy from the code block.

Last edited by IdOp; 26th July 2019 at 07:56 PM.
Reply With Quote