bash-hackers-wiki/howto/calculate-dc/index.html

117 lines
55 KiB
HTML
Raw Normal View History

<!doctype html><html lang=en class=no-js> <head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link href=https://flokoe.github.io/bash-hackers-wiki/howto/calculate-dc/ rel=canonical><link href=../../dict/symlink/ rel=prev><link href=../collapsing_functions/ rel=next><link rel=icon href=../../assets/images/favicon.png><meta name=generator content="mkdocs-1.6.1, mkdocs-material-9.5.44"><title>Calculating with dc - The Bash Hackers Wiki</title><link rel=stylesheet href=../../assets/stylesheets/main.0253249f.min.css><link rel=stylesheet href=../../assets/stylesheets/palette.06af60db.min.css><link rel=preconnect href=https://fonts.gstatic.com crossorigin><link rel=stylesheet href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback"><style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style><script>__md_scope=new URL("../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script></head> <body dir=ltr data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo> <input class=md-toggle data-md-toggle=drawer type=checkbox id=__drawer autocomplete=off> <input class=md-toggle data-md-toggle=search type=checkbox id=__search autocomplete=off> <label class=md-overlay for=__drawer></label> <div data-md-component=skip> <a href=#calculating-with-dc class=md-skip> Skip to content </a> </div> <div data-md-component=announce> </div> <header class=md-header data-md-component=header> <nav class="md-header__inner md-grid" aria-label=Header> <a href=../.. title="The Bash Hackers Wiki" class="md-header__button md-logo" aria-label="The Bash Hackers Wiki" data-md-component=logo> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg> </a> <label class="md-header__button md-icon" for=__drawer> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg> </label> <div class=md-header__title data-md-component=header-title> <div class=md-header__ellipsis> <div class=md-header__topic> <span class=md-ellipsis> The Bash Hackers Wiki </span> </div> <div class=md-header__topic data-md-component=header-topic> <span class=md-ellipsis> Calculating with dc </span> </div> </div> </div> <form class=md-header__option data-md-component=palette> <input class=md-option data-md-color-media data-md-color-scheme=default data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to dark mode" type=radio name=__palette id=__palette_0> <label class="md-header__button md-icon" title="Switch to dark mode" for=__palette_1 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> <input class=md-option data-md-color-media data-md-color-scheme=slate data-md-color-primary=indigo data-md-color-accent=indigo aria-label="Switch to light mode" type=radio name=__palette id=__palette_1> <label class="md-header__button md-icon" title="Switch to light mode" for=__palette_0 hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg> </label> </form> <script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMe
2
</code></pre></div> <p>I used a "here string" present in bash 3.x, ksh93 and zsh. if your shell doesn't support this, you can use <code>echo '1 1+p' | dc</code> or if you have GNU <code>dc</code>, you can use <code>dc -e '1 1 +p'</code>.</p> <p>Of course, you can also just run <code>dc</code> and enter the commands.</p> <p>The classic operations are:</p> <ul> <li>addition: <code>+</code></li> <li>subtraction: <code>-</code></li> <li>division: <code>/</code></li> <li>multiplication: <code>*</code></li> <li>remainder (modulo): <code>%</code></li> <li>exponentiation: <code>^</code></li> <li>square root: <code>v</code></li> </ul> <p>GNU <code>dc</code> adds a couple more.</p> <p>To input a negative number you need to use the <code>_</code> (underscore) character:</p> <div class=highlight><pre><span></span><code>$ dc &lt;&lt;&lt; &#39;1_1-p&#39;
2
</code></pre></div> <p>You can use the <em>digits</em> <code>0</code> to <code>9</code> and the <em>letters</em> <code>A</code> to <code>F</code> as numbers, and a dot (<code>.</code>) as a decimal point. The <code>A</code> to <code>F</code> <strong>must</strong> be capital letters in order not to be confused with the commands specified with lower case characters. A number with a letter is considered hexadecimal:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;&lt; &#39;Ap&#39;
10
</code></pre></div> <p>The <strong>output</strong> is converted to <strong>base 10</strong> by default</p> <h2 id=scale-and-base>Scale And Base<a class=headerlink href=#scale-and-base title="Permanent link">&para;</a></h2> <p><code>dc</code> is a calulator with abitrary precision, by default this precision is 0. thus <code>dc &lt;&lt;&lt; "5 4/p"</code> prints "1".</p> <p>We can increase the precision using the <code>k</code> command. It pops the value at the top of the stack and uses it as the precision argument:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;&lt; &#39;2k5 4/p&#39; # prints 1.25
dc &lt;&lt;&lt; &#39;4k5 4/p&#39; # prints 1.2500
dc &lt;&lt;&lt; &#39;100k 2vp&#39;
1.4142135623730950488016887242096980785696718753769480731766797379907\
324784621070388503875343276415727
</code></pre></div> <p>dc supports <em>large</em> precision arguments.</p> <p>You can change the base used to output (<em>print</em>) the numbers with <code>o</code> and the base used to input (<em>type</em>) the numbers with <code>i</code>:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
20 p# prints 20, output is in base 10
16o # the output is now in base 2 16
20p # prints 14, in hex
16i # the output is now in hex
p # prints 14 this doesn&#39;t modify the number in the stack
10p # prints 10 the output is done in base 16
EOF
</code></pre></div> <p>Note: when the input value is modified, the base is modified for all commands, including <code>i</code>:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
16i 16o # base is 16 for input and output
10p # prints 10
10i # ! set the base to 10 i.e. to 16 decimal
17p # prints 17
EOF
</code></pre></div> <p>This code prints 17 while we might think that <code>10i</code> reverts the base back to 10 and thus the number should be converted to hex and printed as 11. The problem is 10 was typed while the input base 16, thus the base was set to 10 hexadecimal, i.e. 16 decimal.</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
16o16o10p #prints 10
Ai # set the base to A in hex i.e. 10
17p # prints 11 in base 16
EOF
</code></pre></div> <h2 id=stack>Stack<a class=headerlink href=#stack title="Permanent link">&para;</a></h2> <p>There are two basic commands to manipulate the stack:</p> <ul> <li><code>d</code> duplicates the top of the stack</li> <li> <p><code>c</code> clears the stack</p> <p>$ dc &lt;&lt; EOF 2 # put 2 on the stack d # duplicate i.e. put another 2 on the stack *p # multiply and print c p # clear and print EOF 4 dc: stack empty</p> </li> </ul> <p><code>c p</code> results in an error, as we would expect, as c removes everything on the stack. <em>Note: we can use <code>#</code> to put comments in the script.</em></p> <p>If you are lost, you can inspect (i.e. print) the stack using the command <code>f</code>. The stack remains unchanged:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;&lt; &#39;1 2 d 4+f&#39;
6
2
1
</code></pre></div> <p>Note how the first element that will be popped from the stack is printed first, if you are used to an HP calculator, it's the reverse.</p> <p>Don't hesitate to put <code>f</code> in the examples of this tutorial, it doesn't change the result, and it's a good way to see what's going on.</p> <h2 id=registers>Registers<a class=headerlink href=#registers title="Permanent link">&para;</a></h2> <p>The GNU <code>dc</code> manual says that dc has at least <strong>256 registers</strong> depending on the range of unsigned char. I\'m not sure how you are supposed to use the NUL byte. Using a register is easy:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;EOF
12 # put 12 on the stack
sa # remove it from the stack (s), and put it in register &#39;a&#39;
10 # put 10 on the stack
la # read (l) the value of register &#39;a&#39; and push it on the stack
+p # add the 2 values and print
EOF
</code></pre></div> <p>The above snippet uses newlines to embed comments, but it doesn't really matter, you can use <code>echo '12sa10la+p'| dc</code>, with the same results.</p> <p>The register can contain more than just a value, <strong>each register is a stack on its own</strong>.</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;EOF
12sa #store 12 in &#39;a&#39;
6Sa # with a capital S the 6 is removed
# from the main stack and pushed on the &#39;a&#39; stack
lap # prints 6, the value at the top of the &#39;a&#39; stack
lap # still prints 6
Lap # prints 6 also but with a capital L, it pushes the value in &#39;a&#39;
# to the main stack and pulls it from the &#39;a&#39; stack
lap # prints 12, which is now at the top of the stack
EOF
</code></pre></div> <h2 id=macros>Macros<a class=headerlink href=#macros title="Permanent link">&para;</a></h2> <p><code>dc</code> lets you push arbitrary strings on the stack when the strings are enclosed in <code>[]</code>. You can print it with <code>p</code>: <code>dc &lt;&lt;&lt; '[Hello World!]p'</code> and you can evalute it with x: <code>dc &lt;&lt;&lt; '[1 2+]xp'</code>.</p> <p>This is not that interesting until combined with registers. First, let's say we want to calculate the square of a number (don't forget to include <code>f</code> if you get lost!):</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
3 # push our number on the stack
d # duplicate it i.e. push 3 on the stack again
d**p # duplicate again and calculate the product and print
EOF
</code></pre></div> <p>Now we have several cubes to calculate, we could use <code>dd**</code> several times, or use a macro.</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
[dd**] # push a string
sa # save it in register a
3 # push 3 on the stack
lax # push the string &quot;dd**&quot; on the stack and execute it
p # print the result
4laxp # same operation for 4, in one line
EOF
</code></pre></div> <h2 id=conditionals-and-loops>Conditionals and Loops<a class=headerlink href=#conditionals-and-loops title="Permanent link">&para;</a></h2> <p><code>dc</code> can execute a macro stored in a register using the <code>lR x</code> combo, but it can also execute macros conditionally. <code>&gt;a</code> will execute the macro stored in the register <code>a</code>, if the top of the stack is <em>greater than</em> the second element of the stack. Note: the top of the stack contains the last entry. When written, it appears as the reverse of what we are used to reading:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
[[Hello World]p] sR # store in &#39;R&#39; a macro that prints Hello World
2 1 &gt;R # do nothing 1 is at the top 2 is the second element
1 2 &gt;R # prints Hello World
EOF
</code></pre></div> <p>Some <code>dc</code> have <code>&gt;R &lt;R =R</code>, GNU <code>dc</code> had some more, check your manual. Note that the test "consumes" its operands: the 2 first elements are popped off the stack (you can verify that <code>dc &lt;&lt;&lt; "[f]sR 2 1 &gt;R 1 2 &gt;R f"</code> doesn't print anything)</p> <p>Have you noticed how we can <em>include</em> a macro (string) in a macro? and as <code>dc</code> relies on a stack we can, in fact, use the macro recursively (have your favorite control-c key combo ready ;)) :</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
[ [Hello World] p # our macro starts by printing Hello World
lRx ] # and then executes the macro in R
sR # we store it in the register R
lRx # and finally executes it.
EOF
</code></pre></div> <p>We have recursivity, we have test, we have loops:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt; EOF
[ li # put our index i on the stack
p # print it, to see what&#39;s going on
1 - # we decrement the index by one
si # store decremented index (i=i-1)
0 li &gt;L # if i &gt; 0 then execute L
] sL # store our macro with the name L
10 si # let&#39;s give to our index the value 10
lLx # and start our loop
EOF
</code></pre></div> <p>Of course code written this way is far too easy to read! Make sure to remove all those extra spaces newlines and comments:</p> <div class=highlight><pre><span></span><code>dc &lt;&lt;&lt; &#39;[lip1-si0li&gt;L]sL10silLx&#39;
dc &lt;&lt;&lt; &#39;[p1-d0&lt;L]sL10lLx&#39; # use the stack instead of a register
</code></pre></div> <p>I'll let you figure out the second example, it's not hard, it uses the stack instead of a register for the index.</p> <h2 id=next>Next<a class=headerlink href=#next title="Permanent link">&para;</a></h2> <p>Check your dc manual, i haven't decribed everything, like arrays (only documented with "; : are used by bc(1) for array operations" on solaris, probably because <em>echo \'1 0:a 0Sa 2 0:a La 0;ap\' | dc</em> results in //Segmentation Fault (core dump) //, the latest solaris uses GNU dc)</p> <p>You can find more info and dc programs here:</p> <ul> <li><a href=http://en.wikipedia.org/wiki/Dc_(Unix)>http://en.wikipedia.org/wiki/Dc_(Unix)</a></li> </ul> <p>And more example, as well as a dc implementation in python here:</p> <ul> <li><a href=http://en.literateprograms.org/Category:Programming_language:dc>http://en.literateprograms.org/Category:Programming_language:dc</a></li> <li><a href=http://en.literateprograms.org/Desk_calculator_%28Python%29>http://en.literateprograms.org/Desk_calculator_%28Python%29</a></li> </ul> <p>The manual for the 1971 dc from Bell Labs:</p> <ul> <li><a href=http://cm.bell-labs.com/cm/cs/who/dmr/man12.ps>http://cm.bell-labs.com/cm/cs/who/dmr/man12.ps</a> (dead link)</li> </ul> <aside class=md-source-file> <span class=md-source-file__fact> <span class=md-icon title="Last update"> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M21 13.1c-.1 0-.3.1-.4.2l-1 1 2.1 2.1 1-1c.2-.2.2-.6 0-.8l-1.3-1.3c-.1-.1-.2-.2-.4-.2m-1.9 1.8-6.1 6V23h2.1l6.1-6.1zM12.5 7v5.2l4 2.4-1 1L11 13V7zM11 21.9c-5.1-.5-9-4.8-9-9.9C2 6.5 6.5 2 12 2c5.3 0 9.6 4.1 10 9.3-.3-.1-.6-.2-1-.2s-.7.1-1 .2C19.6 7.2 16.2 4 12 4c-4.4 0-8 3.6-8 8 0 4.1 3.1 7.5 7.1 7.9l-.1.2z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 13, 2024</span> </span> <span class=md-source-file__fact> <span class=md-icon title=Created> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M14.47 15.08 11 13V7h1.5v5.25l3.08 1.83c-.41.28-.79.62-1.11 1m-1.39 4.84c-.36.05-.71.08-1.08.08-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8c0 .37-.03.72-.08 1.08.69.1 1.33.32 1.92.64.1-.56.16-1.13.16-1.72 0-5.5-4.5-10-10-10S2 6.5 2 12s4.47 10 10 10c.59 0 1.16-.06 1.72-.16-.32-.59-.54-1.23-.64-1.92M18 15v3h-3v2h3v3h2v-3h3v-2h-3v-3z"/></svg> </span> <span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-date">November 13, 2024</span> </span> </aside> <h2 id=__comments>Comments</h2> <script src=https://giscus.app/client.js data-repo=flokoe/bash-hackers-wiki data-repo-id=R_kgDOJ3Nr6Q data-category="Giscus Page Comments" data-category-id=DIC_kwDOJ3Nr6c4CXq9t data-mapping=pathname data-strict=1 data-reactions-enabled=1 data-emit-metadata=0 data-input-position=top data-theme=preferred_color_scheme data-lang=en data-loading=lazy crossorigin=anonymous async>
</script> <script>
var giscus = document.querySelector("script[src*=giscus]")
/* Set palette on initial load */
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
giscus.setAttribute("data-theme", theme)
}
/* Register event handlers after documented loaded */
document.addEventListener("DOMContentLoaded", function() {
var ref = document.querySelector("[data-md-component=palette]")
ref.addEventListener("change", function() {
var palette = __md_get("__palette")
if (palette && typeof palette.color === "object") {
var theme = palette.color.scheme === "slate" ? "dark" : "light"
/* Instruct Giscus to change theme */
var frame = document.querySelector(".giscus-frame")
frame.contentWindow.postMessage(
{ giscus: { setConfig: { theme } } },
"https://giscus.app"
)
}
})
})
</script> </article> </div> <script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script> </div> <button type=button class="md-top md-icon" data-md-component=top hidden> <svg xmlns=http://www.w3.org/2000/svg viewbox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg> Back to top </button> </main> <footer class=md-footer> <div class="md-footer-meta md-typeset"> <div class="md-footer-meta__inner md-grid"> <div class=md-copyright> Made with <a href=https://squidfunk.github.io/mkdocs-material/ target=_blank rel=noopener> Material for MkDocs </a> </div> </div> </div> </footer> </div> <div class=md-dialog data-md-component=dialog> <div class="md-dialog__inner md-typeset"></div> </div> <script id=__config type=application/json>{"base": "../..", "features": ["navigation.instant", "navigation.tracking", "navigation.tabs", "navigation.sections", "navigation.top", "content.action.view", "content.action.edit", "search.suggest", "search.highlight", "content.code.copy"], "search": "../../assets/javascripts/workers/search.6ce7567c.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script> <script src=../../assets/javascripts/bundle.83f73b43.min.js></script> </body> </html>