You can run Calchemy here: https://rtestardi.github.io/calchemy/calchemy.html
Basic Features
To perform a simple unit conversion, such as 3 meters converted to inches, you could enter the equation (or click/tap on the link):
Calchemy would respond:
= 118.11 inch
To calculate the required horsepower for a motor which could raise a 2000 lbf elevator to the top of a 10 story building (assuming 12 feet per story) in 1 minute, you could enter the equation:
2000 lbf * (10 * 12 feet) / (1 minute) ? horsepower
Indicating that you want to multiply 2000 pounds force by 10 times 12 feet, divide that by 1 minute, and then express the final result in horsepower. Calchemy would respond:
= 7.27273 horsepower
If, on the other hand, you had made a mistake in the original equation and left out the "/ (1 minute)":
2000 lbf * (10 * 12 feet) ? horsepower
Calchemy would have responded with a Dimensional Mismatch indication containing:
Time^-1
Indicating that the left hand side of the equation was missing a factor of 1/Time -- the equation was not dimensionally correct, and therefore, could not be evaluated.
Calchemy can also be used as a simple dimensionless calculator by eliminating the "?" and result unit from the equation. For example, you could enter the equation:
Calchemy would respond with the algebraically correct answer:
= 17
Advanced Features
You could also enter the original equation in the following less explicit form:
2000 lb; 10 stories; 12 feet/story; 1 minute ? horsepower
Indicating that you want to "combine" 2000 pounds, 10 stories, 12 feet/story, and 1 minute in such a way that the equation is dimensionally correct, and then express the final result in horsepower. Calchemy would again respond:
> 2000 poundf * 10 stories * (12 foot / stories) / (1 minute) ? horsepower
= 7.27273 horsepower
Notice above that Calchemy will always show you how it is interpreting your equations, with a line that begins with ">".
This example illustrates the following features:
Solve By Dimensional Analysis
The ";" operator tells Calchemy to use dimensional analysis to determine whether its operands should be in the numerator or the denominator of the equation. In this example, Calchemy placed the first three operands in the numerator and the last operand in the denominator. This allows you to be less involved with the actual mechanics of the equations.
Overloaded Units
The "lb" unit is an overloaded unit, meaning that it has more than one common definition. It is primarily defined as "lbm" (pounds mass) and secondarily defined as "lbf" (pounds force). Calchemy automatically uses the appropriate definition, again based on dimensional analysis. In this example, Calchemy used "lbf". This allows you to naturally use units with multiple common definitions.
Free Units
The "stories" and "story" units are called free units. Free units are units which are not actually understood by Calchemy, except in that they are new and unique dimensions which must "cancel out" in the end. This allows you to enter equations in a more natural format.
Pluralized Units
The "stories" and "story" units also illustrate that Calchemy understands basic pluralization rules for units. This, again, allows you to enter equations in a more natural format.
How does Calchemy work?
"A number is meaningless without units!" -- a mechanical engineering professor at University of Virginia
Every "number" in Calchemy is represented as a structure containing both a coefficient and an array of dimensional exponents:
class Unit {
double coefficient;
int exponents[0..7];
};
The exponents represent the power of each of the various "base dimensions" understood by Calchemy:
exponents[0] = power of MASS (represented as kilograms externally and grams internally) exponents[1] = power of LENGTH (meters) exponents[2] = power of TIME (seconds) exponents[3] = power of TEMP (degrees K) exponents[4] = power of STORAGE (bits) exponents[5] = power of MONEY (dollars) exponents[6] = power of CURRENT (amperes) exponents[7] = power of SUBSTANCE (moles)
The various math operations are applied to both the coefficient and the exponents of each "number", as follows:
- Addition -- only allowed if the left-hand-side (lhs) and right-hand-side (rhs) have identical exponents; result.coefficient = lhs.coefficient + rhs.coefficient; result.exponents = lhs.exponents.
- Subtraction -- only allowed if the left-hand-side (lhs) and right-hand-side (rhs) have identical exponents; result.coefficient = lhs.coefficient - rhs.coefficient; result.exponents = lhs.exponents.
- Multiplication -- result.coefficient = lhs.coefficient * rhs.coefficient; for (i in 0..7) { result.exponents[i] = lhs.exponents[i] + rhs.exponents[i]; }
- Division -- result.coefficient = lhs.coefficient / rhs.coefficient; for (i in 0..7) { result.exponents[i] = lhs.exponents[i] - rhs.exponents[i]; }
- Exponentiation -- only allowed if rhs is dimensionless (i.e., all rhs exponents are 0); result.coefficient = lhs.coefficient ^ rhs.coefficient; for (i in 0..7) { result.exponents[i] = lhs.exponents[i] * rhs.coefficient; }
Then, we define our base units with coefficients of 1.0 and a single (different) exponent equal to 1 for each:
gram = (1.0) [1, 0, 0, 0, 0, 0, 0, 0] meter = (1.0) [0, 1, 0, 0, 0, 0, 0, 0] second = (1.0) [0, 0, 1, 0, 0, 0, 0, 0] deltaK = (1.0) [0, 0, 0, 1, 0, 0, 0, 0] etc.
Scalar numbers are represented by all exponents being 0, like pi:
pi = (3.14159) [0, 0, 0, 0, 0, 0, 0, 0]
Numerator terms are represented by positive exponents and denominator terms are represented by negative exponents.
Then we define derived units in terms of the base dimensions.
For example, since a liter is a cubic decimeter (and a decimeter is 0.1 meter), a liter is defined as:
liter = (0.1 meter)^3
Following the rules above, this becomes:
liter = (0.1^3) [0, 3, 0, 0, 0, 0, 0, 0]
And a newton is a kilogram (and a kilogram is 1000 grams) meter per second^2:
newton = (1000 gram) * meter / second^2
Again, following the rules above, this becomes:
newton = (1000.0) [1, 1, -2, 0, 0, 0, 0, 0]
Ultimately, when we run thru a few more derived units, we come up with a term for horsepower:
horsepower = (745.699) [1, 2, -3, 0, 0, 0, 0, 0]
2 horsepower would of course be:
2 horsepower = (2*745.699) [1, 2, -3, 0, 0, 0, 0, 0]
Coincidentally, a watt is:
watt = (1.0) [1, 2, -3, 0, 0, 0, 0, 0]
Obviously, we can divide a horsepower by a watt and get a dimensionless result:
horsepower/watt = (745.699) [0, 0, 0, 0, 0, 0, 0, 0]
Solving for a Unit
When the user evaluates "expression ? unit", Calchemy simply treats the "?" as a low precedence division -- dividing the result of the left-hand-side by the right-hand-side, using the same rules above! If the result of the divide is dimensionless, then we know we had a "dimensional match", so we print the resulting coefficient along with the name of the "unit" asked for! Otherwise, if the result of the divide is not dimensionless, we print a "dimensional mismatch" error, indicating which exponents need to be added to the left-hand-side to match the right-hand-side.
That's about all there is to it!
Solve By Dimensional Analysis
The tricky part comes when the user uses a ";" in an equation instead of a "*" or "/"! What Calchemy does in response is evaluate the left- and right-hand-sides 4 different ways:
- left * right
- left / right
- (1/left) * right
- 1/(left * right)
If any of these result in a final dimensionless result, that result is printed, along with the interpretation that worked!
Overloaded Units
Units like "lb" may be defined multiple ways (like, as lbf and lbm):
lbf,lb = (4.44822) [1, 1, -2, 0, 0, 0, 0, 0] lbm,lb = (453.592) [1, 0, 0, 0, 0, 0, 0, 0]
Just like with solve by dimensional analysis, when the user uses an overloaded unit like this in an equation, Calchemy evaluates all possible interpretations of the unit!
And again, if any of these result in a final dimensionless result, that result is printed, along with the interpretation that worked!
Free Units
Finally, what happens when the user uses a unit Calchemy does not understand, like "barleycorn" -- oops, we understand that one! -- how about "corneybarrels"... When Calchemy encounters an unknown unit, it simply defines a new base unit for the duration of the equation, and so long as these new base units "cancel out" (i.e., end up with exponent value of 0) when the final result is calculated, Calchemy is happy and prints the result!
The History of Calchemy
The History of Calchemy™, 1988 to Present · rtestardi/calchemy Wiki
Source Code
See the github repository for source code and tests (built right into the webage!) and online help (ditto!).
Richard Testardi