Explain the decimals

Given a decimal in the form of <float>, <precision>, you draw the graphical representation of the decimal part (i.e. fraction) of the float. Examples:

1. Input: 6.75, 4, output:

6||| 7
----


6.75 (first number from the input) is the number to explain, 4 (the second number from the input) is the number of dashes below the pipes. 6 is the floored 6.75, 7 is the ceiled 6.75. The number of pipes is the decimal part of first input number * second input number.

2. Input: 10.5, 6, output:

10|||   11
------

3. Input: 20.16, 12, output

20||          21
------------


.16 actually takes 1.92 pipes, but since I can't draw 1.92 pipes, I ceil it to 2.

4. Input: 1.1, 12, output:

1|           2
------------


.1 is 1.2 pipes in this case, so it's floored to 1 pipe.

5. Also, an edge case. Input: 5, 4 (i.e. the number is an integer), output:

5    6
----


• The number to explain is the positive float, limited only by your language abilities.
• The precision number is an even integer, greater than 2 (i.e. minimal required precision is 4). It can be arbitrary large too.
• >= n.5 pipes are rounded up, to n+1 (i.e 1.5 is rounded to 2 and 2.5 is rounded to 3). < n.5 pipes are rounded to n (i.e. 1.4 is rounded to 1 and 2.4 is rounded to 2).
• If it would be more convenient for your language, you can take the input as an array, e.g. [6.75, 4]. If you take the input in the reversed order, i.e. [4, 6.75], please specify it in your answer.
• Can you be more specific about exactly what the desired output format is? Jan 1 '16 at 11:47
• @isaacg I've shown four example outputs. What's unclear? Jan 1 '16 at 11:52
• There seem to be a few corner cases uncovered. E.g. input 5.0 4: does it draw from 5 to 6 or from 4 to 5, or is either acceptable? Input 1.25 2: does it have 0 or 1 |s, and why (i.e. what's the rounding rule)? Does the first number in the input have to be positive? What's its maximum precision and magnitude? Does the second number in the input have to be positive? If it's negative, do we draw backwards? Jan 1 '16 at 12:19
• @Peter Clarified. Jan 1 '16 at 12:26
• I don't think you've covered the rounding rule. Jan 1 '16 at 13:05

CJam, 32 bytes

l~1md@:X*mo'|*XSe]1$)NW$s,S*'-X*


Takes the precision first and the decimal second, separated by a space.

Run all test cases.

Explanation

l~   e# Read input and evaluate, pushing precision and decimal on the stack.
1md  e# Divmod 1, separating the decimal into integer and fractional part.
@:X  e# Pull up precision, store in X.
*mo  e# Multiply precision by fractional part and round.
'|*  e# Push that many vertical bars.
XSe] e# Pad with length X with spaces.
1$) e# Copy integer part and increment. N e# Push linefeed. W$   e# Copy integer part.
s,   e# Get number of digits as length of string representation.
S*   e# Push that many spaces, to indent the hyphens correctly.
'-X* e# Push X hyphens.

• Yep, seems to work fine. Jan 1 '16 at 14:33

Mathematica, 119 bytes

a=ToString;b=Array;a[c=Floor@#]<>{b["|"&,d=Round[#2#~Mod~1]],b[" "&,#2-d],a[c+1],"
"," "&~b~IntegerLength@c,"-"&~b~#2}&


I tried... Testing:

In[1]:= a=ToString;b=Array;f=a[c=Floor@#]<>{b["|"&,d=Round[#2#~Mod~1]],b[" "&,#2-d],a[c+1],"\n"," "&~b~IntegerLength@c,"-"&~b~#2}&;

In[2]:= f[6.75, 4]

Out[2]= 6||| 7
----

In[3]:= f[10.5, 6]

Out[3]= 10|||   11
------

In[4]:= f[20.16, 12]

Out[4]= 20||          21
------------

In[5]:= f[1.1, 12]

Out[5]= 1|           2
------------

In[6]:= f[5, 4]

Out[6]= 5    6
----

• Could you maybe provide a working demo, or it's not possible? Jan 1 '16 at 13:09

Japt, 47 46 bytes

Uf +'|pA=ºU-Uf)*V c)+SpV-A +Uc +R+SpUk l)+'-pV


Just a bunch of adding and repeating.

Try it online

• (U-Uf) is the same as U%1, saving two bytes. Jan 1 '16 at 20:16

Java, 253206 181 bytes

Saved 47 bytes thanks to @Kenney by inlining conditions and variables used once, and sorting out redundant variables.

Saved 25 bytes again thanks to @Kenney by inlining 2 loops with ternary operators.

Pure String Manipulation:

Inlined loops version (181 bytes):

String m(float f,int p){int g=(int)f,i=0;String h="",q=""+g;int c=q.length();for(;i<c+p;)h+=i++<c?" ":"-";for(i=c;i<p+c;)q+=i++<c+Math.round((f-g)*p)?"|":" ";return q+(g+1)+"\n"+h;}


4 loops version (206 bytes):

String m(float f,int p){int g=(int)f,i=0;String h="",q=""+g;int c=q.length();for(;i++<c;)h+=" ";for(;i<=c+p;i++)h+="-";for(i=c;i<c+Math.round((f-g)*p);i++)q+="|";for(;i++<p+c;)q+=" ";return q+(g+1)+"\n"+h;}


Ungolfed version:

String m(float f,int p){
//initialize some useful values, d is the number of pipes needed
int g=(int)f,d=Math.round((f-g)*p),i=0;
String h="",q=""+g;//append the floored value to the pipe string first
int c=q.length();
for(;i<c;i++)h+=" ";//pad hyphen string with spaces for alignment
for(++i;i<=c+p;i++)h+="-";//append hyphens
for(i=c;i<c+d;i++)q+="|";//append pipes
return q+(g+1)+"\n"+h;}//concatenate the strings in order, separating the strings with a UNIX newline, and return it.


Working example here at ideone.com. The full program accepts STDIN input as <float>,<precision>.

NOTE: Java's Math.round(float) rounds using RoundingMode.HALF_UPas the default, which is the OP's required behaviour.

The output of the test cases provided was diff-matched to what the OP provided.

• I hope you don't mind! You forgot to remove a (never used), setting you at 233. You could save another 23 to get at 210 bytes: replacing q.length() with b saves 13: int g=(int)f, b=(""+g).length(), c=b, i=0;. Incrementing the iterator in the condition of the for saves 6, and inlining d (used once) saves 4: int c = b; for(;i++<b;)h+=" "; for(;i++<=b+p;)h+="-"; for(i=c;i<c+Math.round((f-g)*p);i++)q+="|"; for(;i++<p+b;)q+=" ";. Jan 1 '16 at 21:09
• Also, someone suggested using an actual newline instead of the escape sequence, but since I'm on Windows, that's a CRLF, 2 bytes anyway given the \n Jan 2 '16 at 4:10
• Nice - yes, b became obsolete aswell ;-) You can still save 1 byte in the 2nd for: for(;i++<=c+p;). You could save the file with unix line endings on windows, but unfortunately Java doesn't allow multiline strings.. Jan 2 '16 at 14:31
• @Kenney, no. I tried that. It leads to misaligned hyphens. Java is not the right man for the job, anyway. Jan 2 '16 at 14:32
• I got it down to 181 bytes by using only 2 for loops: for(;i<c+p;)h+=i++<c?" ":"-";for(i=c;i<p+c;)q+=i++<c+Math.round((f-g)*p)?"|":" "; Jan 2 '16 at 14:41

Javascript ES6, 105 104 bytes

(f,p)=>(i=f|0)+("|".repeat(j=(f-i)*p+.5|0)+" ".repeat(p-j))+(i+1)+(
+i).replace(/\d/g," ")+"-".repeat(p)


Saved 1 byte thanks to, um, how do you type ՊՓԼՃՐՊՃՈԲՍԼ anyway?

• Sorry, I didn't realise the dashes were part of the output, I thought they were just there to visualise the spaces.
– Neil
Jan 1 '16 at 22:49
• (f,p)=>(i=f|0)+("|"[r="repeat"](j=(f-i)*p+.5|0)+" "[r](p-j))+(i+1)+("\n"+i).replace(/\d/g," ")+"-"[r](p) Jan 2 '16 at 0:29
• Oh yeah, replace \n with an actual newline. And make sure to wrap it in template strings. Jan 2 '16 at 0:31

(%)=replicate.round
s=show
x!y|(n,m)<-properFraction x=[s n,(y*m)%'|',(y-y*m)%' ',s$n+1,"\n",s n>>" ",y%'-']>>=id  Usage example: *Main> putStrLn$ 20.16 ! 12
20||          21
------------


properFraction splits the decimal into it's integer and fraction part. The output is a list of the parts (initial number, bars, spaces, ...) which is concatenated into a single string (via >>=id).

• Is it possible to see an online demo of this? Jan 1 '16 at 17:22
• @nicael: demo (with a main wrapper for a full program).
– nimi
Jan 1 '16 at 17:25
• Looks like everything's okay (btw: tested there, think that it's a more convenient compiler). Jan 1 '16 at 17:31

MATL, 49 bytes

2#1\tYUbiXK*Yo'|'1bX"tnKw-Z"hb1+YUhht4Y2m13*_45+c


Uses release 6.0.0 of the language/compiler. Runs on Matlab or Octave.

Takes numbers in the same order as in the challenge.

Examples

>> matl
> 2#1\tYUbiXK*Yo'|'1bX"tnKw-Z"hb1+YUhht4Y2m13*_45+c
>
> 20.16
> 12
20||          21
------------

>> matl
> 2#1\tYUbiXK*Yo'|'1bX"tnKw-Z"hb1+YUhht4Y2m13*_45+c
>
> 5
> 4
5    6
----


Explanation

2#1\       % implicit input 1st number. Separate decimal and integer part
tYU        % duplicate integer part and convert to string
biXK*Yo    % input 2nd number. Copy it. Multiply by decimal part of 1st number and round
'|'1bX"    % row vector of as many '|' as needed
tnKw-Z"    % row vector of as many spaces as needed
h          % concat horiontally
b1+YUhh    % integer part of 1st number plus 1. Convert to string. Concat twice
t4Y2m      % detect numbers in this string
13*_45+c   % transform numbers into spaces, and non-numbers into '|'
% implicitly display both strings

• Do you have an online interpreter? Jan 1 '16 at 17:36
• Not yet :-( Runs on Matlab or Octave Jan 1 '16 at 17:37

Perl, 90 bytes

print$f,"|"x($d=.5+($b=pop)*(($a=pop)-($f=0|$a))),$"x(1+$b-$d),$f+1,$/,$"x length$f,"-"x$b


Expects input as commandline arguments. Save in a file (say 90.pl) and run as perl 90.pl 6.75 4

print $f, # floored input (initialized below due to expr nesting) "|" x ($d=.5+              # rounded pipe count (x operator casts to int)
+($b=pop) # second argument (executed first) *( ($a=pop)         # first argument   (executed second)
-($f=0|$a) )      # minus floored first argument = fractional part
),
$"x(1+$b-$d), # spaces$f+1,                      # floored + 1
$/, # newline$"  x length f, # 2nd line alignment "-" xb                   # the 'ruler'


Stackgoat, 31 27 bytes

CFv1%C*D'|^w1P-Y^vHXNY^w'-^


Similar to most of the other answers. I'll see if I can golf more. The input can be comma separated, space separated, or almost anything separated.

Non competing because Stackgoat was made after this challenge

Explanation

CF   // Input, floored, push to stack
v1%  // Decimal part
C*   // Times second part
D    // Duplicate that result
'|^  // Repeat | by previous number
w    // Second input
1P   // Move # of |'s to the top of stack
-    // Subtract
Y^   // Repeat " " by above number
vH   // Ceil first input
X    // Newline
N    // Get length of first #
Y^   // Repeat by spaces
w'-  // Repeat - second input times


Lua, 157 bytes

Long, but can't find a shorter solution

function f(d,n)r=""a=math.floor(d)d,s=d-a,a..r for i=1,#s do r=r.." "end for i=1,n do s,r=s..(i-.5>n*d and" "or"|"),r.."-"end s=s..a+1 return s.."\n"..r end


Ungolfed

function g(d,n)
r=""
a=math.floor(d)
d,s=d-a,a..r                         -- d now contains its decimal part
for i=1,#s do r=r.." "end            -- padding the hyphens
for i=1,n
do
s,r=s..(i-.5>n*d and" "or"|"),r.."-"
-- s is concatenated with a "|" if i-.5>n*d, a space otherwise
end
s=s..a+1
return s.."\n"..r
end


You can test lua online, the following test cases could be useful :)

function f(d,n)r=""a=math.floor(d)d,s=d-a,a..r for i=1,#s do r=r.." "end for i=1,n do s,r=s..(i-.5>n*d and" "or"|"),r.."-"end s=s..a+1 return s.."\n"..r end
print(f(16.75,4))
print(f(5,4))
print(f(20.16,12))


C, 233 231 bytes

#include <stdlib.h>
#include <math.h>
i,n,l;main(c,v)char**v;{double m;l=atol(v[2]);n=(int)(modf(atof(v[1]),&m)*l+0.5);c=printf("%.f",m);for(;i++<l;)putchar(i>n?32:'|');printf("%.f\n",m+1);printf("%*s",c,"");for(;--i;)putchar(45);}


Ungolfed:

#include <stdlib.h>
#include <math.h>
i,n,l;

main(c,v)
char**v;
{
double m;
l=atol(v[2]); /* Get length from command line */
n=(int)(modf(atof(v[1]),&m)*l+0.5); /* Get number of pipes and lower limit */
c=printf("%.f",m); /* print lower limit */

/* print pipes and spaces */
for(;i++<l;)
putchar(i>n?32:'|');

/* print upper limit */
printf("%.f\n",m+1);

/* print spaces before dashes */
printf("%*s",c,"");

/* print dashes */
for(;--i;)
putchar(45);
}


Python 3, 116 108 bytes

def f(F,P):l=int(F);h,p=str(l+1),int((F-l)*P+.5);l=str(l);print(l+"|"*p+" "*(P-p)+h);print(" "*len(l)+"-"*P)


Thank you to Seeq for saving a few characters.

First version:

def f(F,P):
l=int(F)
h,s,p=str(l+1)," ",int((F-l)*P+.5)
l=str(l)
print(l+"|"*p+s*(P-p)+h)
print(s*len(l)+"-"*P)


Ungolfed version:

def frac(F,P):
low = int(F)
high = low+1
pipes = int((F-low)*P+.5)
print(str(low)+"|"*pipes+" "*(P-pipes)+str(high))
print(" "*len(str(low))+"-"*P)

• Could you please provide a working demo? Jan 2 '16 at 19:17
• This trinket.io link should work: trinket.io/python/409b1488f8 Jan 2 '16 at 19:24
• It actually takes less characters to just use the space literal than store it. You can also just join all the lines with ;. You only use h once, so you should inline it, too. Ought to save some chars. Jan 3 '16 at 8:49
• @Seeq Good catch on the space literal. Early on I was printing the white space padding at the end of the second line; after I realize that was unnecessary, I didn't double check the code for savings. The h is trickier. For the concatenation and len function in the last two rows to work, l has to be a string, so h would need to be replaced with str(int(l)+1). Setting h before converting l saves a few characters. Jan 6 '16 at 16:54