Temperature conversion/REXX: Difference between revisions

m
added whitespace.
m (→‎{{header|REXX}}: changed/added comments and whitespace, changed indentations, elided need for FUZZY digits, moved some code into subroutines to make reading easier.)
m (added whitespace.)
 
(16 intermediate revisions by 2 users not shown)
Line 1:
This is the unabridged version of the REXX program to solve the Rosetta Code task of   ''Temperature conversion''.
 
 
=={{header|REXX}}==
Note that conversion from/to the   '''Dalton'''   temperature scale requires natural logarithms   ('''ln'''),   and the   '''pow'''   function.
<lang rexx>/*REXX program converts tem4eratures for fifty-seven different temperature scales. */
 
 
No commenting/explaining was affixed to the higher math functions because it would detract from the logic of the main program.
 
 
<span style='font-family: "Linux Libertine",Georgia,Times,serif;font-size:150%;'>[[REXX]]</span><hr>
 
 
<lang rexx>/*REXX program converts temperatures for fifty─eight different temperature scales. */
/*
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
 
tt tt
tt tt
tttttt tttttt
tttttt eeee mmm mm ppppp eeee rr rr aaaa tttttt uu uu rr rr eee
tt eeeeee mmmmmmmm pppppp eeeeee rrrrrr aaaaa tt uu uu rrrrrr eeeeee
tt ee ee mm mm mm pp pp ee ee rrr rr aa tt uu uu rrr rr ee ee
tt eeeeee mm mm mm pp pp eeeeee rr aaaaaa tt uu uu rr eeeeee
tt eeeeee mm mm mm pppppp eeeeee rr aaaaaaa tt uu uu rr eeeeee
tt tt ee mm mm mm ppppp ee rr aa aa tt tt uu uu rr ee
ttttt eeeee mm mm mm pp eeeee rr aaaaaaa ttttt uuuuuu rr eeeee
ttt eee mm mm mm pp eee rr aaaaaaa ttt uuu uu rr eee
pp
pp
 
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
*/
 
 
call e /*let's see the precision we can use. */
numeric digits length(e) - 1 /*big digits for Planck & DaltonsDalton scale.*/
/*subtract one for the decimal point.*/
parse arg tList /*get the specified temperature lists. */
tList= space(tList) /*elide any and all superfluous blanks.*/
 
 
do until tList='' /*process the list of temperatures. */
parse var tList x ',' tList /*temperatures are separated by commas.*/
x= translate(x, '(((', "[{«") /*support other grouping symbols. */
x= space(x) /*elide any and all superfluous blanks.*/
parse var x z '(' var x z '(' /*handle any comments (if there're any)*/
parse upper var z z ' TO ' ! . /*separate the TO option from number.*/
parse upper var z z 'NOT' not . , noS noE /*separate NOT option from number. */
/*for the NOT keyword, see (below).*/
 
/* *xxx ◄───don't show scales that end in xxx */
/* xxx* ◄─── " " " " begin with xxx */
if not\=='' then do
if left(not, 1) == '*' then noE= substr(not, 2)
if right(not, 1) == '*' then noS= left(not, length(not) - 1)
noL= length(noE || noS)
if noL==0 then call serr "illegal NOT keyword, no leading or trailing * specified."
"illegal NOT keyword, no leading or trailing * specified."
end
 
if !=='' then != "ALL" /*nothing specific, so choose "ALL". */
 
all= (!=='ALL') /*allows specification of the "TO" opt.*/
 
if z=='' then call serr 'no arguments were specified.'
 
_= verify(z, '+-.0123456789') /*a list of valid numberdecimal digs & thingys. */
n= z /*obtain a "backup" copy of Z (number).*/
n=z
 
if _\==0 then do
if _==1 then call serr 'illegal temperature:' z
n= left(z, _-1) /*obtain the number (hopefully). */
u= strip( substr(z, _)) ) /*obtain the temperature unit. */
end
else u= 'k' /*assume kelvin as per task requirement*/
/* ────── */
 
if \datatype(n, 'N') then call serr "illegal number:" n
 
if \all then do /*there is a TO ααα temp. scale. */
call scaleName ! /*process the TO temp. abbreviation.*/
!=sn sn /*assign the full temperature name to !*/
end /*! now contains temp scale full name.*/
 
call scaleName u u /*allow alternate temp. scale spellings*/
call convert2Fahrenheit /*convert a temperature ──↓──► FarhrenheitFahrenheit.*/
 
say right(' ' x, 79, "─") /*show original value & scale (for sep)*/
 
call convert2specific /*convert FarhrenheitFahrenheit ──► specific temp,*/
end /*until tlist='' */ /*this is a biggish DO loop. */
 
 
Line 60 ⟶ 92:
 
 
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────$ subroutine────────────────────────────────────────*/
$: procedure; showDig=8 8 /*only show 8 significant decimal digs.*/
_= commas( format( arg(1), , showDig ) / 1 ) /*format# 8 digits past . and add comma*/
p= pos(., _) /*find position of the decimal point. */
/* [↓] align integers with FP numbers.*/
if p==0 then _= _ || left('', 5 + showDig + 1) /*no decimal point.*/
else _= _ || left('', 5 + showDig - length(_) + p) /*has " " */
 
return right(_, max(60, length(_) ) ) /*return the re-formattedre─formatted argument (#).*/
 
 
/*────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────CONVERT2FAHRENHEIT subroutine─────────────────────────────────────────────────*/
convert2Fahrenheit: /*convert N ──► °ºF temperatures. */
 
/* [↓] 57 differentfifty-eight temperature scales.*/
select
when sn=='ABSOLUTE' then F= n * 9/5 - 459.67
when sn=='AMONTON' then F= n * 8.37209 - 399.163
when sn=='BARNSDORF' then F= n * 6.85714 + 6.85714
Line 86 ⟶ 119:
when sn=='CRUQUIUS' then F= n * 0.409266 - 405.992
when sn=='DALENCE' then F= n * 2.7 + 59
when sn=='DALTON' then F= 273.15 * pow(273.15 / 273.15, n / 100) * 1.8 - 459.67
when sn=='DANIELL' then F= n * 7.27194 + 55.9994
when sn=='DE LA HIRE' then F=(n - 3) / 0.549057
Line 135 ⟶ 168:
otherwise call serr 'invalid temperature scale: ' u
end /*select*/
 
 
return
 
 
/*─────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────CONVERT2SPECIFIC subroutine────────────────────────────────────────────────*/
convert2specific: /*convert NºF ──► °Fxxx temperatures. */
 
K = (F + 459.67) * 5/9 /*compute temperature in kelvin scale. */
a = (1e || (-digits() % 2) - digits() % 20) /*minimum number for Dalton temperature*/
eV = (F + 459.67) / 20888.1 /*compute the number of electron volts.*/
 
 
if ?('ABSOLUTE') then say $( k ) "Absolute"
if ?('AMONTON') then say $( ( F + 399.163 ) / 8.37209 ) "Amonton"
if ?('BARNSDORF') then say $( ( F - 6.85715) / 6.85715 ) "Barnsdorf"
Line 158 ⟶ 191:
if ?('CRUQUIUS') then say $( ( F + 405.992 ) / 0.409266 ) "Cruquius"
if ?('DALENCE') then say $( ( F - 59 ) / 2.7 ) "Dalence"
 
if ?('DALTON') then if k>a then say $(100*ln(k/273.15)/ln(373.15/273.15) ) "Dalton"
if ?('DALTON') then if K>a elsethen say right$("-infinity ", 60 100*ln(k/273.15)/ln(373.15/273.15) ) "Dalton"
else say right("-infinity ", 60) "Dalton"
 
if ?('DANIELL') then say $( ( F - 55.9994 ) / 7.27194 ) "Daniell"
if ?('DE LA HIRE') then say $( F * 0.549057 + 3 ) "De la Hire"
Line 197 ⟶ 232:
if ?('RICHTER') then say $( ( F + 7.45205) * 73/160 ) "Richter"
if ?('RINALDINI') then say $( ( F - 32 ) / 15 ) "Rinaldini"
if ?('ROMER') then say $( ( F - 32 ) * 74/2427 + 7.5 ) "Romer"
if ?('ROSENTHAL') then say $( ( F + 453.581 ) * 86/45 ) "Rosenthal"
if ?('ROYAL SOCIETY') then say $( F * -69/50 + 122.82 ) "Royal Society of London"
Line 210 ⟶ 245:
 
 
/*──────────────────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────SCALENAME subroutine───────────────-────────────────────────────*/
scaleName: parse arg y /*abbreviations ──► temp. short name.*/
yU= translate(y, '-eE', "_éÉ") /*translate some accented characters. */
upper yU /*uppercase version of temperature unit*/
 
if left(yU, 7)=='DEGREES' then yU=substr(yU, 8) /*is this a redundant "degrees" ? ? */
if left(yU, 6)=='DEGREE' then yU=substr(yU, 7) /* " " " " "degree" ? ? */
 
yU= strip(yU) /*elide all leading & trailing blanks. */
_= length(yU) /*obtain the length of the yU value. */
 
if right(yU,1)=='S' & _>1 then yU=left(yU, _-1) /*remove any trailing plural(s). */
Line 225 ⟶ 260:
 
select /*change abbreviations ──► shortname.*/
when abbrev('ABSOLUTE' , yU, 1) then sn= "ABSOLUTE"
when abbrev('AMONTON' , yU) then sn= "AMONTON"
when abbrev('BARNDORF' , yU,2) |,
Line 251 ⟶ 287:
abbrev('CELISU' , yU) |, /* 1% misspelled.*/
abbrev('CELSU' , yU) |, /* 1% misspelled.*/
abbrev('HECTOGRADE' , yU) |,
abbrev('CELSIU' , yU) then sn= "CELSIUS"
when abbrev('CIMANTO' , yU,2) |,
Line 400 ⟶ 437:
 
 
/*──────────────────────────────────────────────────────────────────────────────────────*/
/*──────────────────────────────────one─liner subroutines───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
?: parse arg y 1 yu
?: parse arg y; if not\=='' then do; if noS\=="" then if left(y,noL)==noS then return 0; if noE\=='' then if right(y,noL)==noE then return 0; end; if all | y==! then return 1; return 0
upper yu
commas:procedure; parse arg _; n=_'.9'; #=123456789; b=verify(n,#,"M"); e=verify(n,#'0',,verify(n,#"0.",'M'))-4; do j=e to b by -3; _=insert(",",_,j); end /*j*/; return _
if not\=='' then do
e: e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932; return e
if noS\=="" then if left(yu, noL)==noS then return 0
isInt: return datatype(arg(1), 'W') /*is the argument a whole number (integer)?*/
exp: procedure; parse arg x; ix=x%1; if abs(x-ix)>.5 then ix=ix+sign(x); x=x-ix; z=1; _=1; w=z; do j=1; _=_*x/j; z=(z+_)/1; if znoE\==w'' then leave;w=z;end;if z\right(yu, noL)==0noE then z=z*e()**ix;return z/10
ln: procedure; parse arg x; call e; ig=x>1.5; is=1-2*(ig\==1); ii=0; xx=x; return ln..()end
 
ln..: do while ig & xx>1.5 | \ig & xx<.5;_=e;do k=-1;iz=xx*_**-is;if k>=0 & (ig & iz<1 | \ig & iz>.5) then leave;_=_*_;izz=iz;end;xx=izz; ii=ii+is*2**k; end; x=x*e**-ii-1; z=0;_=-1;p=z;do k=1; _=-_*x; z=z+_/k; if z=p then leave;p=z; end; return z+ii
if all | y==! then return 1
pow: procedure; parse arg x,y; if y=0 then return 1; if x=0 then return 0; if isInt(y) then return x**y; if isInt(1/y) then return root(x,1/y,f); return pow.()
return 0
pow.: if abs(y//1)=.5 then return sqrt(x)**sign(y)*x**(y%1); return exp(y*ln(x))
 
root: procedure; parse arg x 1 ox,y 1 oy; if x=0 | y=1 then return x; if isInt(y) then return rooti(x,y); _=sqrt(x); if y<0 then _=1/_; return _
 
rooti: x=abs(x); y=abs(y); a=digits()+5; g=rootIg(); m=y-1; d=5; do until d==a; d=min(d+d,a); numeric digits d; o=0; do until o=g; o=g; g=format((m*g**y+x)/y/g**m,,d-2); end; end; _=g*sign(ox); if oy<0 then _=1/_; return _
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: procedure; parse arg _ /*insert commas in a number. */
n= _'.9' /*added suffix for VERIFY BIF.*/
#= 123456789 /*a nifty handy-dandy literal.*/
b= verify(n, #, "M") /*find beginning of a number. */
e= verify(n, #'0', , verify(n, #"0.", 'M') ) - 4 /* " end " " " */
 
do j=e to b by -3 /*insert commas right─to─left.*/
_= insert(",", _, j) /*insert a comma every period.*/
end /*j*/
 
return _
 
 
/*──────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x /*obtain the target of SQRT. */
if x=0 then return 0 /*Argument is zero? Return 0.*/
/*This function work for zero.*/
d= digits() /*get # of dec. digs, current.*/
m.= 9 /*set " " " " at start.*/
h= d+6 /*add 6 for rounding concerns.*/
numeric form /*right form of exponentiation*/
numeric digits /*start with nine numeric digs*/
 
/*a way of getting the expon. */
/*No exponent? Then add one. */
parse value format(x, 2, 1, , 0) 'E0' with g "E" _ .
/* [↓] halve the exponent. */
g=g * .5'e'_ % 2 /*a first best guess for sqrt,*/
/*which is 1/2 of the exponent*/
/* [↓] use min number of dec.*/
/* digs for early SQRTs. */
do j=0 while h>9
m.j= h /*calculate # of digits to use*/
h= h % 2 + 1 /*halving the exponent means */
end /*j*/ /* that it'll be doubled as */
/* the M. array will be */
/* processed backwards. [↓] */
do k=j+5 to 0 by -1 /*calculate higher precision. */
numeric digits m.k /*bump the decimal digits. */
g= (g + x / g) * .5 /*calculate SQRT approximation*/
end /*k*/
return g / 1 /*this normalizes the sqrt #. */
 
 
/*──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/
?: parse arg y; if not\=='' then do; if noS\=="" then if left(y, noL)==noS then return 0; if noE\=='' then if right(y, noL)==noE then return 0; end; if all | y==! then return 1; return 0
e: e = 2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932; return e /*112 useful decimal digits. */
isInt: return datatype(arg(1), 'W') /*is the argument a whole number (integer)? */
exp: procedure; parse arg x; ix=x%1; if abs(x-ix)>.5 then ix=ix+sign(x); x=x-ix; z=1; _=1; w=z; do j=1; _=_*x/j; z=(z+_)/1; if z==w then leave; w=z; end; if z\==0 then z= z * e()**ix; return z/1
ln: procedure; parse arg x; call e; ig=x>1.5; is=1-2*(ig\==1); ii=0; xx=x; return ln..()
ln..: do while ig & xx>1.5 | \ig & xx<.5;_=e;do k=-1;iz=xx*_**-is;if k>=0 & (ig & iz<1 | \ig & iz>.5) then leave;_=_*_;izz=iz;end;xx=izz; ii=ii+is*2**k; end; x=x*e**-ii-1; z=0;_=-1;p=z;do k=1; _=-_*x;z=z+_/k; if z=p then leave;p=z; end; return z+ii
pow: procedure; parse arg x,y; if y=0 then return 1; if x=0 then return 0; if isInt(y) then return x**y; if isInt(1/y) then return root(x,1/y,f); return pow.()
pow.: if abs(y//1)=.5 then return sqrt(x)**sign(y)*x**(y%1); return exp(y*ln(x))
root: procedure; parse arg x 1 ox,y 1 oy; if x=0 | y=1 then return x; if isInt(y) then return rooti(x,y); _=sqrt(x); if y<0 then _=1/_; return _
rooti: x=abs(x); y=abs(y); a= digits() + 5; g=rootIg(); m= y-1; d=5; do until d==a; d=min(d+d, a); numeric digits d; o=0; do until o=g; o=g; g=format( (m*g**y+x) /y/g**m, , d-2); end; end; _= g * sign(ox); if oy<0 then _= 1/_; return _
rootIg: numeric form;parse value format(x,2,1,,0) 'E0' with ? 'E' _ .; return (? / y'E'_ % y) + (x>1)
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1) /*pluralizer.*/
serr: say; say '***error***'; say; say arg(1); say; say; exit 13
/*────────────────────────────────────────────────────────────────────────────────────────────*/
sqrt: procedure; parse arg x; if x=0 then return 0; d=digits(); m.=9; numeric form; h=d+6
numeric digits; parse value format(x,2,1,,0) 'E0' with g "E" _ .; g=g *.5'e'_ % 2
do j=0 while h>9; m.j=h; h=h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g=(g+x/g)*.5; end /*k*/
return g/1
</lang>