<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mingye Yang</title>
    <description>The latest articles on DEV Community by Mingye Yang (@eric_ymy_48).</description>
    <link>https://dev.to/eric_ymy_48</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4217739%2F72639919-16b8-454c-aed5-455b8dc25ff5.jpg</url>
      <title>DEV Community: Mingye Yang</title>
      <link>https://dev.to/eric_ymy_48</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eric_ymy_48"/>
    <language>en</language>
    <item>
      <title>Peptide calculator math: the water volume is the free variable</title>
      <dc:creator>Mingye Yang</dc:creator>
      <pubDate>Fri, 30 Oct 2026 17:18:28 +0000</pubDate>
      <link>https://dev.to/eric_ymy_48/peptide-calculator-math-the-water-volume-is-the-free-variable-4im4</link>
      <guid>https://dev.to/eric_ymy_48/peptide-calculator-math-the-water-volume-is-the-free-variable-4im4</guid>
      <description>&lt;p&gt;A 10 mg vial and a U-100 syringe tell you almost everything you need. The one number they don't give you is how much water to add, and every number after that depends on it.&lt;/p&gt;

&lt;p&gt;This post is about that variable and the code that handles it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three units, two dimensions
&lt;/h2&gt;

&lt;p&gt;Most of the bugs I hit came from treating one dimension as another.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;mg / mcg&lt;/strong&gt; is how much peptide. Before mixing, it's dry powder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mL&lt;/strong&gt; is how much liquid. That includes the water you add.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;units&lt;/strong&gt; is a mark on the syringe, not a volume you can hold. On a U-100 barrel, 1 unit = 0.01 mL, so 100 units = 1 mL.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A milligram is not a millilitre. Concentration is the only place they meet.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two formulas
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UNITS_PER_ML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;concentration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vialMg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;waterMl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;vialMg&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;waterMl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="c1"&gt;// mg per mL&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;unitsToDraw&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetMg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetMg&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;conc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;UNITS_PER_ML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Worked example, the one I keep coming back to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;10 mg vial + 2 mL water   = 5 mg/mL
250 mcg target            = 0.25 mg
0.25 / 5                  = 0.05 mL
0.05 x 100                = 5 units
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add 4 mL instead of 2 and the same 250 mcg becomes 10 units. Same vial, same target, different draw. That is why "I take 10 units" from someone else's post is not information you can use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inverting the question
&lt;/h2&gt;

&lt;p&gt;Most calculators take the water volume as an input. But the water is the one thing you actually get to choose. Concentration is derived from it.&lt;/p&gt;

&lt;p&gt;So the interesting direction is: given vial mg, a target amount and a syringe capacity, which water volumes produce a draw you can physically read?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;vialMg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;targetMg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;syringeMl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxWaterMl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxWaterMl&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waterMl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;step&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;      &lt;span class="c1"&gt;// integer steps, formatted on output&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;conc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vialMg&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;waterMl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;targetMg&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;conc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;UNITS_PER_ML&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;syringeMl&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;UNITS_PER_ML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// does not fit the barrel&lt;/span&gt;
    &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;waterMl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;conc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The loop counts in integer steps and formats afterwards. Incrementing a float by 0.1 inside the loop gives you &lt;code&gt;0.30000000000000004&lt;/code&gt;, and that number eventually ends up in a UI.&lt;/p&gt;

&lt;p&gt;Then rank by how close the draw lands to a graduation the barrel actually has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;roundingGap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;units&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;graduation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nearest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;units&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;graduation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;graduation&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;nearest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;errorUnits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nearest&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;units&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a candidate needs 7.5 units on a barrel marked in whole units, the arithmetic is correct and the measurement is still wrong. Small &lt;code&gt;errorUnits&lt;/code&gt; first, then smaller water volume.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;vial&lt;/th&gt;
&lt;th&gt;target&lt;/th&gt;
&lt;th&gt;water&lt;/th&gt;
&lt;th&gt;concentration&lt;/th&gt;
&lt;th&gt;draw&lt;/th&gt;
&lt;th&gt;units&lt;/th&gt;
&lt;th&gt;readable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5 mg&lt;/td&gt;
&lt;td&gt;250 mcg&lt;/td&gt;
&lt;td&gt;1 mL&lt;/td&gt;
&lt;td&gt;5 mg/mL&lt;/td&gt;
&lt;td&gt;0.05 mL&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 mg&lt;/td&gt;
&lt;td&gt;250 mcg&lt;/td&gt;
&lt;td&gt;1.5 mL&lt;/td&gt;
&lt;td&gt;3.33 mg/mL&lt;/td&gt;
&lt;td&gt;0.075 mL&lt;/td&gt;
&lt;td&gt;7.5&lt;/td&gt;
&lt;td&gt;no, half a mark&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5 mg&lt;/td&gt;
&lt;td&gt;250 mcg&lt;/td&gt;
&lt;td&gt;2 mL&lt;/td&gt;
&lt;td&gt;2.5 mg/mL&lt;/td&gt;
&lt;td&gt;0.1 mL&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The bugs that matter
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;mcg vs mg.&lt;/strong&gt; 250 mcg is 0.25 mg. One dropped factor of 1000 is enough to be dangerous, so both units stay parseable and the conversion happens at the boundary, never mid-calculation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Syringe capacity is a hard constraint.&lt;/strong&gt; A 0.3 mL barrel tops out at 30 units. A suggested volume that produces 45 units is not a plan, it's an error message.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vial capacity.&lt;/strong&gt; "Add 2 mL" does not fit into a 3 mL vial that already holds powder and air. A suggestion that cannot be carried out is worse than no suggestion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Floating point.&lt;/strong&gt; Covered above, but it bit me twice: once in the loop, once when formatting to two decimals and dropping a trailing zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Already reconstituted vials.&lt;/strong&gt; If it's already mixed, the water volume is unknown and the search above is meaningless. That has to be a separate mode where concentration comes from the user instead of being computed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it refuses to do
&lt;/h2&gt;

&lt;p&gt;The tool never picks a dose, a schedule or a product. It converts numbers you supply and shows the steps. Reconstitution is a measurement problem. Choosing what to measure is a different problem, and not one a static page should answer.&lt;/p&gt;

&lt;p&gt;If you want to poke at the implementation: &lt;a href="https://peptidecal.net/" rel="noopener noreferrer"&gt;peptide calculator&lt;/a&gt; — the &lt;a href="https://peptidecal.net/calculators/peptide-reconstitution-calculator/" rel="noopener noreferrer"&gt;reconstitution mode&lt;/a&gt; and the &lt;a href="https://peptidecal.net/calculators/peptide-dosage-calculator/" rel="noopener noreferrer"&gt;dosage view&lt;/a&gt; are the two entry points.&lt;/p&gt;

&lt;p&gt;If you find a rounding case I got wrong, tell me.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>ui</category>
    </item>
  </channel>
</rss>
