1

I'm in the process of setting up a chemical model that takes inputs as mols, but discretely simulates the molecules (i.e., each molecule is one entity). As a result, I need to be able to calculate out the proportions as whole numbers. For example if I have 0.01 mols of A and 0.002 mols of B I would scale that out to 10 units of A and 2 units of B. However, this code is pretty inelegant and assumes that all molar counts will be less than 1.0, i.e.,

// Find the exponent to offset the value
NumberFormat format = new DecimalFormat("0.#E0");       
String value = format.format(smallest);
int exponent = Integer.parseInt(value.substring(value.indexOf("E") + 1));

// Scale to whole numbers
exponent = Math.abs(exponent) + 1;
for (int ndx = 0; ndx < input.size(); ndx++) {
    input.get(ndx).count = (long)(input.get(ndx).mols * Math.pow(10, exponent)); 
}

Is there an efficient algorithm to perform decimal shift on arbitrary inputs (ex., 1.1 mols of A, 0.11 mols of B, 0.001 mols of C befomes 1100 units of A, 110 units of B, and 1 unit of C)?

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
rjzii
  • 14,236
  • 12
  • 79
  • 119
  • Multiply both numbers by 10 until they become integer. Then, [reduce the resulting fraction](https://stackoverflow.com/questions/7777142/how-to-simplify-a-fraction). – Nico Schertler Feb 02 '18 at 18:36
  • You could convert each floating point number to a numerator/denominator pair ((2^e * 1man) / (2^24)) and then work on the explicit fractions instead. You get into some difficulties with decimal values not being exactly representable in binary though. – SirGuy Feb 02 '18 at 18:39
  • @NicoSchertler Not exactly very elegant though, I suspected that might be the only option, but was hoping that there might be something else out besides that. – rjzii Feb 02 '18 at 18:39
  • [std::frexp](http://en.cppreference.com/w/cpp/numeric/math/frexp) would probably help out. – SirGuy Feb 02 '18 at 18:40
  • @rjzii Why isn't that elegant enough for you? If you are bothered by the "multiply until" part, then this can be done analytically depending on your data type. – Nico Schertler Feb 02 '18 at 18:41
  • @NicoSchertler Too much time reading Knuth and Dijkstra. – rjzii Feb 02 '18 at 20:38
  • @greybeard [Be nice](https://stackoverflow.com/help/be-nice), don't be a jerk. From the body of the question it's clear it was a typo. – rjzii Feb 03 '18 at 17:22
  • @greybeard You know you are allow to edit questions, right? – rjzii Feb 03 '18 at 18:09
  • 1
    "Next badge: Strunk & White". – greybeard Feb 03 '18 at 18:56
  • There are some nuances regarding floating point representation than you need to make some decisions about. Simple exact decimals like .1 cannot be exactly represented as floats or doubles in most languages. That's why many languages have classes like Java's BigDecimal or python's decimal.Decimal. If you can avoid ever storing the target value in a float or double you'll be in a better position to solve your problem. – President James K. Polk Feb 04 '18 at 16:05
  • @JamesKPolk Indeed. The good thing is that since I know exactly what the input is supposed to represent (i.e., molar concentration of compounds in a solution) I can make some assumptions about the problem that simplify things a bit (ex., no repeating decimals.) – rjzii Feb 04 '18 at 20:15

1 Answers1

1

Start with Algorithm for simplifying decimal to fractions to turn the decimal ratio into a fraction, and the fraction is your answer.

btilly
  • 43,296
  • 3
  • 59
  • 88
  • -1 You might need to elaborate a lot more, but after reading that a couple times, I'm not sure you understood the problem. Having something like 3/2 and 1/4 could be useful, but ultimately there is still work that is needed to shift the values. See the latest revision to the question for more information. – rjzii Feb 03 '18 at 18:13
  • @rjzii If shifting by a multiple of 10 always works, you can just figure out how many decimal places for each, then shift by the larger number of decimal places. – btilly Feb 03 '18 at 18:32
  • Yes, there was a bit of a need for someone to rubber duck the problem at the office yesterday, and that's the naive code I have in place. However, I can't help the feeling that I might have seen some sort of fast shift algorithm in "Hacker's Delight" or something. – rjzii Feb 03 '18 at 18:36
  • @rjzii That said, if you have a repeating decimal, the link I sent you to will help you figure out the fraction it comes from. – btilly Feb 04 '18 at 17:25