Chemical calculator: Difference between revisions

Content added Content deleted
No edit summary
Line 992: Line 992:
C27H46O -> 386.664
C27H46O -> 386.664
Uue -> 315.000</pre>
Uue -> 315.000</pre>

=={{header|Delphi}}==
{{trans|Go}}
<lang Delphi>
program ChemicalCalculator;

{$APPTYPE CONSOLE}

{$R *.res}

uses
System.SysUtils,
System.Generics.Collections;

{$I AtomicMass.inc }

type
TAtomicMass = class(TDictionary<string, Double>)
public
constructor Create(Keys: array of string; Values: array of Double); overload;
end;

{ TAtomicMass }

constructor TAtomicMass.Create(Keys: array of string; Values: array of Double);
var
i: Integer;
begin
inherited Create;

Assert(length(Keys) = Length(Values), 'Keys and values must have the same size');
if Length(Keys) = 0 then
exit;

for i := 0 to High(Keys) do
Add(Keys[i], Values[i]);
end;

var
AtomicMassData: TAtomicMass;

function Evaluate(s: string): Double;
var
sum: Double;
symbol: string;
number: string;
c: char;
i, n: Integer;
begin
s := s + '[';
symbol := '';
number := '';

for i := 1 to s.Length do
begin
c := s[i];
if ('@' <= c) and (c <= '[') then
begin
n := 1;
if not number.IsEmpty then
n := StrToInt(number);
if not symbol.IsEmpty then
sum := sum + AtomicMassData[symbol] * n;
if c = '[' then
Break;
symbol := c;
number := '';
Continue;
end;

if ('a' <= c) and (c <= 'z') then
begin
symbol := symbol + c;
Continue;
end;

if ('0' <= c) and (c <= '9') then
begin
number := number + c;
Continue;
end;

raise Exception.Create('Unexpected symbol ' + c + ' in molecule');
end;
Result := sum;
end;

function ReplaceFirst(text, search, replace: string): string;
var
pos: Integer;
begin
pos := text.IndexOf(search);
if (pos < 0) then
Exit(text);
Result := text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
end;

function ReplaceParens(s: string): string;
var
letter: Char;
start: Integer;
i: Integer;
expr, symbol: string;
begin
letter := 's';
while True do
begin
start := s.IndexOf('(');
if (start = -1) then
Break;

for i := start + 1 to s.Length - 1 do
begin
if s[i + 1] = ')' then
begin
expr := s.Substring(start + 1, i - start - 1);
symbol := '@' + letter;
s := ReplaceFirst(s, s.Substring(start, i + 1 - start), symbol);
if not (AtomicMassData.ContainsKey(symbol)) then
AtomicMassData.Add(symbol, Evaluate(expr))
else
AtomicMassData[symbol] := Evaluate(expr);
inc(letter);
Break;
end;

if (s[i + 1] = '(') then
start := i;
end;
end;
Result := s;
end;


var
molecules: array of string;
i: Integer;
mass: Double;

begin
molecules := ['H', 'H2', 'H2O', 'H2O2', '(HO)2', 'Na2SO4', 'C6H12',
'COOH(C(CH3)2)3CH3', 'C6H4O2(OH)4', 'C27H46O', 'Uue'];
AtomicMassData := TAtomicMass.Create(ATOMIC_MASS_SYMBOL, ATOMIC_MASS_VALUE);

for i := 0 to 10 do
begin
mass := Evaluate(ReplaceParens(molecules[i]));
Writeln(format('%17s -> %7s', [molecules[i], FormatFloat('####.000',mass)]));
end;

AtomicMassData.Free;
readln;
end.
</lang>
Include file with Atomic Mass Constants ('''AtomicMass.inc''').
<lang Delphi>
const
ATOMIC_MASS_SIZE = 101;
ATOMIC_MASS_SYMBOL: array[0..ATOMIC_MASS_SIZE - 1] of string = ('H', 'He',
'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', 'P', 'S',
'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu',
'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo',
'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba',
'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm',
'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb',
'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', 'Pu', 'Am',
'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Uue', 'Ubn');

ATOMIC_MASS_VALUE: array[0..ATOMIC_MASS_SIZE - 1] of double = (1.008, 4.002602,
6.94, 9.0121831, 10.81, 12.011, 14.007, 15.999, 18.998403163, 20.1797,
22.98976928, 24.305, 26.9815385, 28.085, 30.973761998, 32.06, 35.45, 39.948,
39.0983, 40.078, 44.955908, 47.867, 50.9415, 51.9961, 54.938044, 55.845,
58.933194, 58.6934, 63.546, 65.38, 69.723, 72.630, 74.921595, 78.971, 79.904,
83.798, 85.4678, 87.62, 88.90584, 91.224, 92.90637, 95.95, 101.07, 102.90550,
106.42, 107.8682, 112.414, 114.818, 118.710, 121.760, 127.60, 126.90447,
131.293, 132.90545196, 137.327, 138.90547, 140.116, 140.90766, 144.242, 145,
150.36, 151.964, 157.25, 158.92535, 162.500, 164.93033, 167.259, 168.93422,
173.054, 174.9668, 178.49, 180.94788, 183.84, 186.207, 190.23, 192.217,
195.084, 196.966569, 200.592, 204.38, 207.2, 208.98040, 209, 210, 222, 223,
226, 227, 232.0377, 231.03588, 238.02891, 237, 244, 243, 247, 247, 251, 252,
257, 315, 299);
</lang>




=={{header|Factor}}==
=={{header|Factor}}==