Multiplication tables

Revision as of 10:49, 24 December 2009 by 83.76.111.63 (talk) (added factor implementation)

Produce a formatted 12×12 multiplication table of the kind memorised by rote when in primary school.

Task
Multiplication tables
You are encouraged to solve this task according to the task description, using any language you may know.

Only print the top half triangle of products.

ALGOL 68

Works with: ALGOL 68 version Standard - no extensions to language used
Works with: ALGOL 68G version Any - tested with release 1.18.0-9h.tiny

<lang Algol68>main:(

 INT max = 12;
 INT width = ENTIER(log(max)*2)+1;
 STRING empty = " "*width, sep="|", hr = "+" + (max+1)*(width*"-"+"+");
 FORMAT ifmt = $g(-width)"|"$; # remove leading zeros #
 printf(($gl$, hr));
 print(sep + IF width<2 THEN "x" ELSE " "*(width-2)+"x " FI + sep);
 FOR col TO max DO printf((ifmt, col)) OD;
 printf(($lgl$, hr));
 FOR row TO max DO
   [row:max]INT product;
   FOR col FROM row TO max DO product[col]:=row*col OD;
   STRING prefix=(empty+sep)*(row-1);
   printf(($g$, sep, ifmt, row, $g$, prefix, ifmt, product, $l$))
 OD;
 printf(($gl$, hr))

)</lang> Output:

+---+---+---+---+---+---+---+---+---+---+---+---+---+
| x |  1|  2|  3|  4|  5|  6|  7|  8|  9| 10| 11| 12|
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|  1|  1|  2|  3|  4|  5|  6|  7|  8|  9| 10| 11| 12|
|  2|   |  4|  6|  8| 10| 12| 14| 16| 18| 20| 22| 24|
|  3|   |   |  9| 12| 15| 18| 21| 24| 27| 30| 33| 36|
|  4|   |   |   | 16| 20| 24| 28| 32| 36| 40| 44| 48|
|  5|   |   |   |   | 25| 30| 35| 40| 45| 50| 55| 60|
|  6|   |   |   |   |   | 36| 42| 48| 54| 60| 66| 72|
|  7|   |   |   |   |   |   | 49| 56| 63| 70| 77| 84|
|  8|   |   |   |   |   |   |   | 64| 72| 80| 88| 96|
|  9|   |   |   |   |   |   |   |   | 81| 90| 99|108|
| 10|   |   |   |   |   |   |   |   |   |100|110|120|
| 11|   |   |   |   |   |   |   |   |   |   |121|132|
| 12|   |   |   |   |   |   |   |   |   |   |   |144|
+---+---+---+---+---+---+---+---+---+---+---+---+---+

C

<lang c>#include <math.h>

  1. include <stdio.h>

int main(int argc, char *argv[]) {

   int max = 12;
   const char *format = " %*d";
   const char *format2 = "%*s%c";
   int	dgts;
   int i,j;

   dgts = (int)(.99+ log10(1.0*max*max));
   
   printf(format2, dgts, "",'x');
   for (i=1; i <= max; i++) printf(format, dgts, i);
   printf("\n\n");
   
   for (j=1; j<=max; j++) {
     printf(format, dgts, j);
     for(i=1; i<j; i++) printf(format2, dgts, "",' ');
     for(i=j; i<=max; i++) printf(format, dgts, i*j);
     printf("\n");
   }
   printf("\n");
   return 0;

}</lang> Output:

   x   1   2   3   4   5   6   7   8   9  10  11  12

   1   1   2   3   4   5   6   7   8   9  10  11  12
   2       4   6   8  10  12  14  16  18  20  22  24
   3           9  12  15  18  21  24  27  30  33  36
   4              16  20  24  28  32  36  40  44  48
   5                  25  30  35  40  45  50  55  60
   6                      36  42  48  54  60  66  72
   7                          49  56  63  70  77  84
   8                              64  72  80  88  96
   9                                  81  90  99 108
  10                                     100 110 120
  11                                         121 132
  12                                             144

C++

This is a slightly more-generalized version that takes any minimum and maximum table value, and formats the table columns.

<lang cpp>#include <iostream>

  1. include <iomanip>
  2. include <cmath> // for log10()
  3. include <algorithm> // for max()

size_t get_table_column_width(const int min, const int max) {

   unsigned int abs_max = std::max(max*max, min*min);
   // abs_max is the largest absolute value we might see.
   // If we take the log10 and add one, we get the string width
   // of the largest possible absolute value.
   // Add one for a little whitespace guarantee.
   size_t colwidth = 1 + std::log10(abs_max) + 1;
   // If only one of them is less than 0, then some will
   // be negative.
   bool has_negative_result = (min < 0) && (max > 0);
   // If some values may be negative, then we need to add some space
   // for a sign indicator (-)
   if(has_negative_result)
       colwidth++;
   return colwidth;

}

void print_table_header(const int min, const int max) {

   size_t colwidth = get_table_column_width(min, max);
   // table corner
   std::cout << std::setw(colwidth) << " ";
   
   for(int col = min; col <= max; ++col)
   {
       std::cout << std::setw(colwidth) << col;
   }
   // End header with a newline and blank line.
   std::cout << std::endl << std::endl;

}

void print_table_row(const int num, const int min, const int max) {

   size_t colwidth = get_table_column_width(min, max);
   // Header column
   std::cout << std::setw(colwidth) << num;
   // Spacing to ensure only the top half is printed
   for(int multiplicand = min; multiplicand < num; ++multiplicand)
   {
       std::cout << std::setw(colwidth) << " ";
   }
   // Remaining multiplicands for the row.
   for(int multiplicand = num; multiplicand <= max; ++multiplicand)
   {
       std::cout << std::setw(colwidth) << num * multiplicand;
   }
   // End row with a newline and blank line.
   std::cout << std::endl << std::endl;

}

void print_table(const int min, const int max) {

   // Header row
   print_table_header(min, max);
   // Table body
   for(int row = min; row <= max; ++row)
   {
       print_table_row(row, min, max);
   }

}

int main() {

   print_table(1, 12);
   return 0;

} </lang>

Output:

       1   2   3   4   5   6   7   8   9  10  11  12

   1   1   2   3   4   5   6   7   8   9  10  11  12

   2       4   6   8  10  12  14  16  18  20  22  24

   3           9  12  15  18  21  24  27  30  33  36

   4              16  20  24  28  32  36  40  44  48

   5                  25  30  35  40  45  50  55  60

   6                      36  42  48  54  60  66  72

   7                          49  56  63  70  77  84

   8                              64  72  80  88  96

   9                                  81  90  99 108

  10                                     100 110 120

  11                                         121 132

  12                                             144

Common Lisp

<lang lisp> (do ((m 0 (if (= 12 m) 0 (1+ m)))

    (n 0 (if (= 12 m) (1+ n) n)))
   ((= n 13))
 (if (zerop n)
     (case m
       (0 (format t "  *|"))
       (12 (format t "  12~&---+------------------------------------------------~&"))
       (otherwise
        (format t "~4,D" m)))
     (case m
       (0 (format t "~3,D|" n))
       (12 (format t "~4,D~&" (* n m)))
       (otherwise
        (if (>= m n)
            (format t "~4,D" (* m n))
            (format t "    "))))))

</lang>

E

<lang e> def size := 12

 println(`{|style="border-collapse: collapse; text-align: right;"`)
 println(`|`)
 for x in 1..size {
   println(`|style="border-bottom: 1px solid black; " | $x`)
 }
 for y in 1..size {
   println(`|-`)
     println(`|style="border-right: 1px solid black;" | $y`)
   for x in 1..size {
     println(`|  ${if (x >= y) { x*y } else {""}}`)
   }
 }
 println("|}")</lang>

Targets MediaWiki markup. Output:

1 2 3 4 5 6 7 8 9 10 11 12
1  1  2  3  4  5  6  7  8  9  10  11  12
2    4  6  8  10  12  14  16  18  20  22  24
3      9  12  15  18  21  24  27  30  33  36
4        16  20  24  28  32  36  40  44  48
5          25  30  35  40  45  50  55  60
6            36  42  48  54  60  66  72
7              49  56  63  70  77  84
8                64  72  80  88  96
9                  81  90  99  108
10                    100  110  120
11                      121  132
12                        144

Factor

<lang factor>USING: io kernel math math.parser math.ranges sequences ; IN: multiplication-table

print-row ( n -- )
   [ number>string 2 CHAR: space pad-head write " |" write ]
   [ 1 - [ "    " write ] times ]
   [
       dup 12 [a,b]
       [ * number>string 4 CHAR: space pad-head write ] with each
   ] tri nl ;
print-table ( -- )
   "    " write
   1 12 [a,b] [ number>string 4 CHAR: space pad-head write ] each nl
   "   +" write
   12 [ "----" write ] times nl
   1 12 [a,b] [ print-row ] each ;</lang>
       1   2   3   4   5   6   7   8   9  10  11  12
   +------------------------------------------------
 1 |   1   2   3   4   5   6   7   8   9  10  11  12
 2 |       4   6   8  10  12  14  16  18  20  22  24
 3 |           9  12  15  18  21  24  27  30  33  36
 4 |              16  20  24  28  32  36  40  44  48
 5 |                  25  30  35  40  45  50  55  60
 6 |                      36  42  48  54  60  66  72
 7 |                          49  56  63  70  77  84
 8 |                              64  72  80  88  96
 9 |                                  81  90  99 108
10 |                                     100 110 120
11 |                                         121 132
12 |                                             144

Forth

<lang forth>

multiplication-table
 cr 2 spaces  13 2 do i 4 u.r loop
 cr
 13 2 do
   cr i 2 u.r
   13 2 do
     i j < if 4 spaces else i j * 4 u.r then
   loop
 loop ;

</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran>program multtable implicit none

 integer :: i, j, k
   write(*, "(a)") " x|   1   2   3   4   5   6   7   8   9  10  11  12"
   write(*, "(a)") "--+------------------------------------------------"
   do i = 1, 12
     write(*, "(i2, a)", advance="no") i, "|"

do k = 2, i

   	  write(*, "(a4)", advance="no") ""
       end do
   	do j = i, 12
         write(*, "(i4)", advance="no") i*j
       end do
       write(*, *)
   end do

end program multtable</lang>

Haskell

<lang haskell>import Control.Monad import Text.Printf

main = do

   putStrLn $ "   x" ++ concatMap fmt [1..12]
   zipWithM_ f [1..12] $ iterate ("    " ++) ""
 where f n s = putStrLn $ fmt n ++ s ++ concatMap (fmt . (*n)) [n..12]
       fmt n = printf "%4d" (n :: Int)</lang>

J

<lang j> multtable=: <:/~ * */~

  format=: 'b4.0' 8!:2 ]
  (('*' ; ,.) ,. ({. ; ])@format@multtable) >:i.12

┌──┬────────────────────────────────────────────────┐ │* │ 1 2 3 4 5 6 7 8 9 10 11 12│ ├──┼────────────────────────────────────────────────┤ │ 1│ 1 2 3 4 5 6 7 8 9 10 11 12│ │ 2│ 4 6 8 10 12 14 16 18 20 22 24│ │ 3│ 9 12 15 18 21 24 27 30 33 36│ │ 4│ 16 20 24 28 32 36 40 44 48│ │ 5│ 25 30 35 40 45 50 55 60│ │ 6│ 36 42 48 54 60 66 72│ │ 7│ 49 56 63 70 77 84│ │ 8│ 64 72 80 88 96│ │ 9│ 81 90 99 108│ │10│ 100 110 120│ │11│ 121 132│ │12│ 144│ └──┴────────────────────────────────────────────────┘</lang>

JavaScript

<lang html4strict><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" > <title>12 times table</title> <script type='text/javascript'>

   function multiplication_table(n, target) {
       var table = document.createElement('table');
       var row = document.createElement('tr');
       var cell = document.createElement('th');
       cell.appendChild(document.createTextNode('x'));
       row.appendChild(cell);
       for (var x = 1; x <=n; x++) {
           cell = document.createElement('th');
           cell.appendChild(document.createTextNode(x));
           row.appendChild(cell);
       }
       table.appendChild(row);
       for (var x = 1; x <=n; x++) {
           row = document.createElement('tr');
           cell = document.createElement('th');
           cell.appendChild(document.createTextNode(x));
           row.appendChild(cell);
           var y;
           for (y = 1; y < x; y++) {
               cell = document.createElement('td');
               cell.appendChild(document.createTextNode('\u00a0'));
               row.appendChild(cell);
           }
           for (; y <= n; y++) {
               cell = document.createElement('td');
               cell.appendChild(document.createTextNode(x*y));
               row.appendChild(cell);
           }
           table.appendChild(row);
       }
       target.appendChild(table);
   }

</script> <style type='text/css'>

   body {font-family: sans-serif;}
   table {border-collapse: collapse;}
   th, td {border: 1px solid black; text-align: right; width: 4ex;}

</style> </head> <body onload="multiplication_table(12, document.getElementById('target'));">

</body> </html></lang>

Outputs (minus the style):

x123456789101112
1123456789101112
2 4681012141618202224
3  9121518212427303336
4   162024283236404448
5    2530354045505560
6     36424854606672
7      495663707784
8       6472808896
9        819099108
10         100110120
11          121132
12           144

OCaml

Translation of: C

<lang ocaml>let () =

 let max = 12 in
 let fmax = float_of_int max in
 let dgts = int_of_float (ceil (log10 (fmax *. fmax))) in
 let fmt = Printf.printf " %*d" dgts in
 let fmt2 = Printf.printf "%*s%c" dgts in
 fmt2 "" 'x';
 for i = 1 to max do fmt i done;
 print_string "\n\n";
 for j = 1 to max do
   fmt j;
   for i = 1 to pred j do fmt2 "" ' '; done;
   for i = j to max do fmt (i*j); done;
   print_newline()
 done;
 print_newline()</lang>

Perl

<lang perl>our $max = 12; our $width = length($max**2) + 1;

printf "%*s", $width, $_ foreach 'x|', 1..$max; print "\n", '-' x ($width - 1), '+', '-' x ($max*$width), "\n"; foreach my $i (1..$max) { printf "%*s", $width, $_

           foreach "$i|", map { $_ >= $i and $_*$i } 1..$max;

print "\n"; }</lang>

Output:

  x|   1   2   3   4   5   6   7   8   9  10  11  12
---+------------------------------------------------
  1|   1   2   3   4   5   6   7   8   9  10  11  12
  2|       4   6   8  10  12  14  16  18  20  22  24
  3|           9  12  15  18  21  24  27  30  33  36
  4|              16  20  24  28  32  36  40  44  48
  5|                  25  30  35  40  45  50  55  60
  6|                      36  42  48  54  60  66  72
  7|                          49  56  63  70  77  84
  8|                              64  72  80  88  96
  9|                                  81  90  99 108
 10|                                     100 110 120
 11|                                         121 132
 12|                                             144

Python

<lang python>>>> size = 12 >>> width = len(str(size**2)) >>> for row in range(-1,size+1): if row==0: print("─"*width + "┼"+"─"*((width+1)*size-1)) else: print("".join("%*s%1s" % ((width,) + (("x","│") if row==-1 and col==0 else (row,"│") if row>0 and col==0 else (col,"") if row==-1 else ("","") if row>col else (row*col,""))) for col in range(size+1)))


 x│  1   2   3   4   5   6   7   8   9  10  11  12 

───┼───────────────────────────────────────────────

 1│  1   2   3   4   5   6   7   8   9  10  11  12 
 2│      4   6   8  10  12  14  16  18  20  22  24 
 3│          9  12  15  18  21  24  27  30  33  36 
 4│             16  20  24  28  32  36  40  44  48 
 5│                 25  30  35  40  45  50  55  60 
 6│                     36  42  48  54  60  66  72 
 7│                         49  56  63  70  77  84 
 8│                             64  72  80  88  96 
 9│                                 81  90  99 108 
10│                                    100 110 120 
11│                                        121 132 
12│                                            144 

>>> </lang>

The above works with Python 3.X, which uses Unicode strings by default.
Declaring a file type of UTF-8 and adding a u to all string literals to transform them into Unicode literals would make the above work in Python 2.X. (As would using ASCII minus, plus, and pipe characters: "-", "+", "|"; instead of the non-ASCII chars used to draw a frame).

Ruby

<lang ruby>def multiplication_table(n)

 puts "    " + ((" %3d" * n) % (1..n).to_a)
 1.upto(n) do |x|
   print "%3d " % x
   1.upto(x-1) {|y| print "    "}
   x.upto(n)   {|y| print " %3d" % (x*y)}
   puts ""
 end

end

multiplication_table 12</lang>

Tcl

<lang tcl>puts " x\u2502 1 2 3 4 5 6 7 8 9 10 11 12" puts \u0020\u2500\u2500\u253c[string repeat \u2500 48] for {set i 1} {$i <= 12} {incr i} {

   puts -nonewline [format "%3d" $i]\u2502[string repeat " " [expr {$i*4-4}]]
   for {set j 1} {$j <= 12} {incr j} {

if {$j >= $i} { puts -nonewline [format "%4d" [expr {$i*$j}]] }

   }
   puts ""

}</lang> Output:

  x│   1   2   3   4   5   6   7   8   9  10  11  12
 ──┼────────────────────────────────────────────────
  1│   1   2   3   4   5   6   7   8   9  10  11  12
  2│       4   6   8  10  12  14  16  18  20  22  24
  3│           9  12  15  18  21  24  27  30  33  36
  4│              16  20  24  28  32  36  40  44  48
  5│                  25  30  35  40  45  50  55  60
  6│                      36  42  48  54  60  66  72
  7│                          49  56  63  70  77  84
  8│                              64  72  80  88  96
  9│                                  81  90  99 108
 10│                                     100 110 120
 11│                                         121 132
 12│                                             144