Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

You can determine the volume of objects based on a given set of dimensions:

  • The volume of a sphere can be determined using a single number, the radius (r)
  • The volume of a cylinder can be determined using two numbers, the radius (r) and the height (h)
  • The volume of a box can be determined using three numbers, the length (l), width (w) and the height (h)
  • The volume of an irregular triangular pyramid can be determined using four numbers, the side lengths (a, b, c) and the height (h).

The challenge is to determine the volume of an object given one of the following inputs:

  • A single number (r) or (r, 0, 0, 0) => V = 4/3*pi*r^3
  • Two numbers (r, h) or (r, h, 0, 0) => V = pi*r^2*h
  • Three numbers (l, w, h) or (l, w, h, 0) => V = l*w*h
  • Four numbers (a, b, c, h) => V = (1/3)*A*h, where A is given by Heron's formula: A = 1/4*sqrt((a+b+c)*(-a+b+c)*(a-b+c)*(a+b-c))

Rules and clarifications:

  • The input can be both integers and/or decimals
  • You can assume all input dimensions will be positive
  • If Pi is hard coded it must be accurate up to: 3.14159.
  • The output must have at least 6 significant digits, except for numbers that can be accurately represented with fewer digits. You can output 3/4 as 0.75, but 4/3 must be 1.33333 (more digits are OK)
    • How to round inaccurate values is optional
  • Behaviour for invalid input is undefined
  • Standard rules for I/O. The input can be list or separate arguments

This is code golf, so the shortest solution in bytes win.

Test cases:

calc_vol(4)
ans =  268.082573106329

calc_vol(5.5, 2.23)
ans =  211.923986429533

calc_vol(3.5, 4, 5)
ans =  70

calc_vol(4, 13, 15, 3)
ans =  24

Related, but different.

share|improve this question
1  
Is the order of the dimensions required to be the order stated in the question? – Mego Mar 8 at 23:33
    
Related – Sp3000 Mar 9 at 0:05
    
@Mego, you may choose... – Stewie Griffin Mar 9 at 11:11
    
@StewieGriffin Varargs and getting at dynamically sized arrays is a pain in my language (at least for me, a beginner at it). Can I provide four functions to handle each arg count? – cat Mar 16 at 22:45
    
You can have a fixed sized array with the last elements set to zero if need be. That should cover it I think? Or you can overload functions as in the Haskell answer. You can't have different functions with different names. – Stewie Griffin Mar 16 at 22:52

12 Answers 12

up vote 4 down vote accepted

MATL, 57 53 51 44 bytes

3^4*3/YP*GpG1)*YP*GpG0H#)ts2/tb-p*X^3/*XhGn)

Input is an array with 1, 2, 3 or 4 numbers.

Try it online!

Explanation

Instead of using nested if loops, which is expensive in terms of bytes, this computes four possible results for any input, and then picks the appropriate result depending on input length.

When computing the results, even though only one of them needs to be valid, the others cannot give errors. This means for example that indexing the fourth element of the input is not allowed, because the input may have less than four elements.

                    % take input implicitly
3^4*3/YP*           % compute a result which is valid for length-1 input:
                    % each entry is raised to 3 and multiplied by 4/3*pi
G                   % push input
pG1)*YP*            % compute a result which is valid for length-2 input:
                    % product of all entries, times first entry, times pi
G                   % push input
p                   % compute a result which is valid for length-3 input:
                    % product of all entries
G                   % push input
0H#)ts2/tb-p*X^3/*  % compute a result which is valid for length-4 input:
                    % shorter version of Heron's formula applied on all
                    % entries except the last, times last entry, divided by 3
Xh                  % collect all results in a cell array
G                   % push input
n)                  % pick appropriate result depending on input length
                    % display implicitly
share|improve this answer
    
What rendition of Heron's formula are you using? – VTCAKAVSMoACE Mar 9 at 23:13
    
@CoolestVeto The one with the semiperimeter. First formula from here – Luis Mendo Mar 9 at 23:17
    
Well done @DonMuesli. I managed it using "only" 34 bytes more in MATLAB =) – Stewie Griffin Mar 15 at 17:31

Vitsy, 49 bytes

I thought you handed this one to me on a plate, but I found an unresolved bug to work around. Didn't hurt me, though.

lmN
3^43/*P*
2^*P*
**
v:++2/uV3\[V}-]V3\*12/^v*3/

Basically, with the input being a certain length for different functions, you spoon feed me my method syntax for doing this stuff. So, yay, success!

Explanation, one line at a time:

lmN
l   Get the length of the stack.
 m  Go to the line index specified by the top item of the stack (the length).
  N Output as a number.

3^43/*P*
3^
          Put to the power of 3.
  43/*    Multiply by 4/3.
      P*  Multiply by π

2^*P*
2^     Put to the second power.
  *    Multiply the top two items.
   P*  Multiply by π

**
**     Multiply the top three items of the stack.

v:++2/uV3\[V}-]V3\*12/^v*3/
v                            Save the top item as a temp variable.
 :                           Duplicate the stack.
  ++                         Sum the top three values.
    2/                       Divide by two.
      u                      Flatten the top stack to the second to top.
       V                     Capture the top item of the stack (semiperimeter) 
                             as a permanent variable.
        3\[   ]              Do the stuff in the brackets 3 times.
           V}-               Subtract the semiperimeter by each item.
               V             Push the global var again.
                3\*          Multiply the top 4 items.
                   12/^      Square root.
                       v*    Multiply by the temp var (the depth)
                         3/  Divide by three.

Input is accepted as command line arguments in the exact reverse as they appear in the question, with no trailing zeroes.

Try it online!

As an aside, here's something that's currently in development.

Java w/ Vitsy Package

Note that this package is work in progress; this is just to show how this will work in the future (documentation for this is not yet uploaded) and it is not golfed, and is a literal translation:

import com.VTC.vitsy;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;

public class Volume {
    public static void main(String[] args) {
        Vitsy vitsyObj = new Vitsy(false, true);
        vitsyObj.addMethod(new Vitsy.Method() {
            public void execute() {
                vitsyObj.pushStackLength();
                vitsyObj.callMethod();
                vitsyObj.outputTopAsNum();
            }
        });
        vitsyObj.addMethod(new Vitsy.Method() {
            public void execute() {
                vitsyObj.push(new BigDecimal(3));
                vitsyObj.powerTopTwo();
                vitsyObj.push(new BigDecimal(4));
                vitsyObj.push(new BigDecimal(3));
                vitsyObj.divideTopTwo();
                vitsyObj.multiplyTopTwo();
                vitsyObj.pushpi();
                vitsyObj.multiplyTopTwo();
            }
        });
        vitsyObj.addMethod(new Vitsy.Method() {
            public void execute() {
                vitsyObj.push(new BigDecimal(2));
                vitsyObj.powerTopTwo();
                vitsyObj.multiplyTopTwo();
                vitsyObj.pushpi();
                vitsyObj.multiplyTopTwo();
            }
        });
        vitsyObj.addMethod(new Vitsy.Method() {
            public void execute() {
                vitsyObj.multiplyTopTwo();
                vitsyObj.multiplyTopTwo();
            }
        });
        vitsyObj.addMethod(new Vitsy.Method() {
            public void execute() {
                vitsyObj.tempVar();
                vitsyObj.cloneStack();
                vitsyObj.addTopTwo();
                vitsyObj.addTopTwo();
                vitsyObj.push(new BigDecimal(2));
                vitsyObj.divideTopTwo();
                vitsyObj.flatten();
                vitsyObj.globalVar();
                vitsyObj.push(new BigDecimal(3));
                vitsyObj.repeat(new Vitsy.Block() {
                    public void execute() {
                        vitsyObj.globalVar();
                        vitsyObj.rotateRight();
                        vitsyObj.subtract();
                    }
                });
                vitsyObj.globalVar();
                vitsyObj.push(new BigDecimal(3));
                vitsyObj.repeat(new Vitsy.Block() {
                    public void execute() {
                        vitsyObj.multiplyTopTwo();
                    }
                });
                vitsyObj.push(new BigDecimal(1));
                vitsyObj.push(new BigDecimal(2));
                vitsyObj.divideTopTwo();
                vitsyObj.powerTopTwo();
                vitsyObj.tempVar();
                vitsyObj.multiplyTopTwo();
                vitsyObj.push(new BigDecimal(3));
                vitsyObj.divideTopTwo();
            }
        });
        vitsyObj.run(new ArrayList(Arrays.asList(args)));
    }
}
share|improve this answer
1  
Definitely the right tool for the job – Mego Mar 8 at 23:48

C, 100 97 bytes

#define z(a,b,c,d) d?d*sqrt(4*a*a*b*b-pow(a*a+b*b-c*c,2))/12:c?a*b*c:3.14159*(b?a*a*b:4/3.*a*a*a)

edit 1: remove unnecessary decimal ., thanks Immibis!

share|improve this answer
2  
Can't 4./3. just be 4/3.? And can 2. and 12. just be 2 and 12? – immibis Mar 9 at 0:07
    
You are absolutely correct. Thanks! – Josh Mar 9 at 14:57

JavaScript ES6, 129 126 125 116 114 90 bytes

Saved lots of bytes (9) with a wonderful formula, thanks to Stewie Griffin! Since input must be nonzero, variable? will suffice for a defining-check.

with(Math){(a,b,c,h,Z=a*a)=>h?sqrt(4*Z*b*b-(D=Z+b*b-c*c)*D)/4:c?a*b*c:b?PI*Z*b:4/3*PI*Z*a}

Test it out!

with(Math){Q = (a,b,c,h,Z=a*a)=>h?sqrt(4*Z*b*b-(D=Z+b*b-c*c)*D)/4:c?a*b*c:b?PI*Z*b:4/3*PI*Z*a}
console.log = x => o.innerHTML += x + "<br>";

testCases = [[4], [5.5, 2.23], [3.5, 4, 5], [4, 13, 15, 3]];
redo = _ => (o.innerHTML = "", testCases.forEach(A => console.log(`<tr><td>[${A.join(", ")}]` + "</td><td> => </td><td>" + Q.apply(window, A) + "</td></tr>")));
redo();
b.onclick = _ => {testCases.push(i.value.split(",").map(Number)); redo();}
*{font-family:Consolas,monospace;}td{padding:0 10px;}
<input id=i><button id=b>Add testcase</button><hr><table id=o></table>

share|improve this answer
    
Thanks! It sure is a lot shorter! – Cᴏɴᴏʀ O'Bʀɪᴇɴ Mar 8 at 19:53
5  
With math? Seems legit. – VTCAKAVSMoACE Mar 8 at 20:34
    
This errors on Chrome 48, Uncaught SyntaxError: Unexpected token = (referring to Z=a*a) – Patrick Roberts Mar 9 at 16:05
    
@PatrickRoberts Use Firefox. It allows for default parameters inside lambdas. – Cᴏɴᴏʀ O'Bʀɪᴇɴ Mar 9 at 16:17
    
I can't seem to get the 4-arg version to work... and you never use the value of h, which seems a bit of an oversight. – Neil Mar 12 at 0:20

Haskell, 114 109 107 101 99 bytes

v[r]=4/3*pi*r^3
v[r,h]=pi*r^2*h
v[x,y,z]=x*y*z
v[a,b,c,h]=h/12*sqrt(4*a^2*b^2-(a^2+b^2-c^2)^2)

Takes a list of numbers and returns a volume. Call it like

v[7]

for a sphere, etc. The function is polymorphic for any type that implements sqrt (so, basically Float or Double).

It's not going to win any contests for brevity. But note how readable it is. Even if you don't really know Haskell, you can tell what it does quite easily. Haskell's pattern matching syntax makes it really easy to define strange functions that do something totally different depending on the shape of the input.

share|improve this answer
1  
(1/3)*(1/4)*h,,, why not h/12? Saves you a lot of bytes! – Stewie Griffin Mar 9 at 11:00
1  
Also, the variant of Heron's eq that Conor uses seems to be a lot shorter. – Stewie Griffin Mar 9 at 11:16
    
@StewieGriffin Apparently yes. :-} – MathematicalOrchid Mar 9 at 12:09
    
Haskell is only readable for infix math, which I don't find readable. Then you get into . and # and $ and it becomes Mathematica Soup. – cat Mar 17 at 15:33

PowerShell, 165 161 bytes

param($a,$b,$c,$h)((($h/12)*[math]::Sqrt(($a+$b+$c)*(-$a+$b+$c)*($a-$b+$c)*($a+$b-$c))),(($a*$b*$c),((($p=[math]::PI)*$b*$a*$a),($p*$a*$a*$a*4/3))[!$b])[!$c])[!$h]

So ... Many ... Dollars ... (31 of the 161 characters are $, for 19.25% of the code) ... but, saved 4 bytes thanks to Stewie Griffin!

We take in four inputs, and then progressively index into pseudo-ternary statements based on them in reverse order. E.g., the outside (..., ...)[!$h] tests whether the fourth input is present. If so, the !$h will equal 0 and the first half is executed (the volume of an irregular triagonal pyramid). Otherwise, !$h with $h = $null (as it's uninitialized) will equal 1, so it goes to the second half, which itself is a pseudo-ternary based on [!$c] and so on.

This is likely close to optimal, since the supposedly-shorter formula that (e.g.) Cᴏɴᴏʀ O'Bʀɪᴇɴ is using is actually 2 bytes longer in PowerShell thanks to the lack of a ^ operator ... The only real savings comes from (1/3)*(1/4)*A*$h golfing to A*$h/12, and setting $p later to save a couple bytes instead of the lengthy [math]::PI call.

share|improve this answer
    
Thanks, @StewieGriffin! – TimmyD Mar 9 at 13:22

CJam, 67 66 bytes

q~0-_,([{~3#4*P*3/}{~\_**P*}{:*}{)\a4*(a\[1W1]e!..*+::+:*mq*C/}]=~

I will work on shortening it soon. Try it online!

Explanation to come.

share|improve this answer

Seriously, 65 59 55 bytes

`kd@;Σ½╗"╜-"£Mπ╜*√*3@/``kπ``ª*╦*``3;(^/4*╦*`k,;lD(E@i(ƒ

Try it online!

Explanation

This one is a doozy. I'm going to break the explanation into multiple parts.

Main body:

`...``...``...``...`k,;lD(E@i(ƒ
`...``...``...``...`k            push 4 functions to a list
                     ,;lD        push input, len(input)-1
                         (E      get the function at index len(input)-1
                           @i(   flatten the input list
                              ƒ  execute the function

Function 0:

3;(^/4*╦*
3;(^       push 3, r^3
    /      divide (r^3/3)
     4*    multiply by 4 (4/3*r^3)
       ╦*  multiply by pi (4/3*pi*r^3)

Function 1:

ª*╦*
ª     r^2
 *    multiply by h (r^2*h)
  ╦*  multiply by pi (pi*r^2*h)

Function 2:

kπ  listify, product (l*w*h)

Function 3 (21 bytes; nearly half the program length!)

kd@;Σ½╗"╜-"£Mπ╜*√*3@/
kd@                    listify, dequeue h, bring [a,b,c] back on top
   ;Σ½                       dupe, sum, half (semiperimeter)
      ╗                push to register 0
       "╜-"£M          map: push s, subtract (s-x for x in (a,b,c))
             π         product
              ╜*√      multiply by s, sqrt (Heron's formula for area of the base)
                 *3@/  multiply by h, divide by 3 (1/3*A*h)
share|improve this answer

Matlab, 78 bytes

@(a,b,c,d)pi*a^2*(4/3*a*~b+b*~c)+a*b*c*~d+d/12*(4*a^2*b^2-(a^2+b^2-c^2)^2)^.5;

Quite sure it can't get any shorter than this. ~b, ~c and ~d, are 0 if each of the dimensions are non-zero. A formula with a zero dimension will just give zero. That way, each of the formulas can simply be summed. No if and else required.

Call it like this (or try it online here):

g=@(a,b,c,d)pi*a^2*(4/3*a*~b+b*~c)+a*b*c*~d+d/12*(4*a^2*b^2-(a^2+b^2-c^2)^2)^.5;

g(4,0,0,0)
ans =  268.082573106329

g(5.5,2.23,0,0)
ans =  211.923986429533

g(3.5,4,5,0)
ans =  70

g(4,13,15,3)
ans =  24
share|improve this answer
1  
What a madness of variables :-) Yes, this seems hard to shorten any further – Luis Mendo Mar 15 at 17:42
    
Maybe add a link to try it online? ideone.com/6VZF9z – Luis Mendo Mar 15 at 17:44
1  
Thanks for the link Luis :-) – Stewie Griffin Mar 15 at 18:00

Python 3 2, 127 119 116 bytes

Credit to somebody and Mego for all their help with golfing. Credit also to Cᴏɴᴏʀ O'Bʀɪᴇɴ and Josh as I borrowed parts of their answers for this one.

def v(a,b,c,d):z=a*a;P=3.14159;print filter(int,[max(0,(4*z*b*b-(z+b*b-c*c)**2))**.5*d/12,a*b*c,P*z*b,P*z*a*4/3])[0]

Ungolfed:

def v(a, b, c, d):
    z = a*a
    p = 3.14159
    s = filter(int,[max(0,(4*z*b*b-(z+b*b-c*c)**2))**.5*d/12,a*b*c,P*z*b,P*z*a*4/3])
    print s[0]
share|improve this answer
    
Golfed more: def v(a,b,c,d):z=a*a;p=355/113;return[x for x in[(4*z*b*b-(z+b*b-c*c)**2)**.5*d/12,a*b*c,p*z*b,p*z*a*4/3]if x][0], assuming input is padded with 0s. – Mars Ultor Mar 10 at 7:14
    
Also, if you use Python 2 instead, you can do def v(a,b,c,d):z=a*a;P=3.14159;return filter(int,[(4*z*b*b-(z+b*b-c*c)**2)**.5*d/12,a*b*c,P*z*b,P*z*a*4/3])[0] – Mars Ultor Mar 10 at 7:49

Mathematica, 114 (103)

Pure function: 114

Which[(l=Length@{##})<2,4.Pi/3#1^3,l<3,#1^2.Pi#2,l<4,#1#2#3,l<5,(4#1^2#2^2-(#1^2+#2^2-#3^2)^2)^.5#4/12]~Quiet~All&

Ungolfed:

fun = Which[
  (l = Length@{##}) < 2,
    4. Pi/3 #1^3,
  l < 3,
    #1^2 Pi #2, 
  l < 4,
    #1 #2 #3, 
  l < 5,
    (4 #1^2 #2^2 - (#1^2 + #2^2 - #3^2)^2)^.5 #4/12
]~Quiet~All &

Usage:

fun[4]
268.083
fun[5.5, 2.23]
211.924
fun[3.5, 4, 5]
70.
fun[4, 13, 15, 3]
24.

If named functions are allowed: 103

f[r_]:=4.Pi/3r^3
f[r_,h_]:=r^2.Pi h
f[l_,w_,h_]:=l w h
f[a_,b_,c_,h_]:=(4a^2b^2-(a^2+b^2-c^2)^2)^.5h/12

Usage:

f[4]
268.083
f[5.5, 2.23]
211.924
f[3.5, 4, 5]
70.
f[4, 13, 15, 3]
24.
share|improve this answer
1  
#1==#, I think Quiet[x_]:=Quiet[x,All] and π (Alt-P on a Mac) fits in extended ASCII. – CalculatorFeline Mar 10 at 21:11
    
Can't you replace #1 #2 #3 with 1##? Don't forget #==#1 – CalculatorFeline Mar 15 at 18:30

Factor, 783 bytes

Well, this took forever.

USING: arrays combinators io kernel locals math math.constants math.functions quotations.private sequences sequences.generalizations prettyprint ;
: 1explode ( a -- x y ) dup first swap 1 tail ;
: 3explode ( a -- b c d ) 1explode 1explode 1explode drop ;
: spr ( r -- i ) first 3 ^ 4 3 / pi * swap * ;
: cyl ( r -- i ) 1explode 1explode drop 2 ^ pi swap * * ; : cub ( v -- i ) 1 [ * ] reduce ;
: A ( x a -- b d ) reverse dup dup dup 0 [ + ] reduce -rot 3explode neg + + -rot 3explode - + 3array swap 3explode + - 1array append 1 [ * ] reduce sqrt .25 swap * ;
: ilt ( a -- b c  ) V{ } clone-like dup pop swap A 1 3 / swap pick * * ;
: volume ( v -- e ) dup length { { [ 1 = ] [ spr ] } { [ 2 = ] [ cyl ] } { [ 3 = ] [ cub ] } { [ 4 = ] [ ilt ] } [ "bad length" throw ] } cond print ;

Call { array of numbers } volume .

share|improve this answer
    
Holy smokes! My head is about to ... explode! – Stewie Griffin Mar 17 at 16:29
    
@StewieGriffin :P I totally forgot to shorten the names of the functions. Won't help much, though. – cat Mar 17 at 17:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.