Multiplication tables

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

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

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

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=: |:@(] *"0 1 ]\)

  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>

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 >>> for row in range(-1,size+1): if row==0: print("─"*3 + "┼"+"─"*(4*size-1)) else: print("".join("%3s%1s" % (("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).

The code works fine for all values of integer 0 <= size <= 31 as above that, table numbers can get greater than the three digits allotted to them in the output formatting. This is a reasonable limitation for this format of multiplication table as other considerations, such as the width of the printed line are also excessive for large values of size.

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