# Print the f × f times table

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e
00 03 06 09 0c 0f 12 15 18 1b 1e 21 24 27 2a 2d
00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
00 05 0a 0f 14 19 1e 23 28 2d 32 37 3c 41 46 4b
00 06 0c 12 18 1e 24 2a 30 36 3c 42 48 4e 54 5a
00 07 0e 15 1c 23 2a 31 38 3f 46 4d 54 5b 62 69
00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78
00 09 12 1b 24 2d 36 3f 48 51 5a 63 6c 75 7e 87
00 0a 14 1e 28 32 3c 46 50 5a 64 6e 78 82 8c 96
00 0b 16 21 2c 37 42 4d 58 63 6e 79 84 8f 9a a5
00 0c 18 24 30 3c 48 54 60 6c 78 84 90 9c a8 b4
00 0d 1a 27 34 41 4e 5b 68 75 82 8f 9c a9 b6 c3
00 0e 1c 2a 38 46 54 62 70 7e 8c 9a a8 b6 c4 d2
00 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1


# Specifications:

• You can print the hex values in uppercase.
• Your lines can end with a trailing space and the program output can end with a trailing newline.
• Every hex value must be padded to 2 digits with 0s as shown.

This is , so the shortest answer (measured in bytes) wins.

• Related – Luis Mendo Dec 17 '16 at 1:18
• Also related – Digital Trauma Dec 17 '16 at 1:45
• Multiplication tables don't usually include factor 0... :-) – Luis Mendo Dec 17 '16 at 1:55
• @Luis Mendo: How else will school children be able to memorize what 0 times a number is? :P – milk Dec 17 '16 at 1:56
• Darn, I wanted to make a solution using hexdump, but that groups into 4-byte blocks. :( – HyperNeutrino Feb 26 '17 at 1:04

# Python 2, 112 109 100 96 73 Bytes

R=range(16)
for i in R:print' '.join('0'*(i*j<16)+hex(i*j)[2:]for j in R)


Try it online!

• saved 3 bytes: Thanks to Wheat Wizard; predefined range(16) into R which is used twice.
• saved 9 bytes: Crunched up the earlier if statement into a single statement.
• saved 4 bytes: crunched the statements in 2nd 'for' block.
• saved 23 bytes: Thanks @J843136028: used list comprehension
• You can predefine range(16) with R=range(16) and replace each instance of range(16) with R. – Sriotchilism O'Zaic Dec 17 '16 at 5:07
• You can use list comprehension and starred expressions to save variables. See my answer (currently below). – 0WJYxW9FMN Aug 21 '17 at 18:51
• Thanks, @J843136028 I did some changes and got to 73 bytes, and kept it a bit different than your answer. :) – officialaimm Aug 22 '17 at 11:41

# VBA, 66 bytes

For m=0To 15:For n=0To 15:?Right(Hex(256+n*m)&" ",3);:Next:?:Next


Enter in Immediate window in VBA editor. Adding 256 to the expression to convert to hexadecimal is only shorter because the concatenater "&" requires a space after it to separate from alphabetic strings.

• Alternatively you could use For m=0To 15:For n=0To 15:?Right("0"+Hex(n*m)+" ",3);:Next:?:Next for the same bytecount (which is 65 not 66 by the way) – Taylor Scott Aug 22 '17 at 17:57

# APL (Dyalog), 444336 33 bytes

10 bytes saved thanks to @Adám

Crossed out 44 is still regular 44 ;(

↑,/{(⎕D,⎕A)[16 16⊤⍵],' '}¨∘.×⍨⍳16


Uses ⎕IO←0.

Try it online!

How?

∘.×⍨⍳16 - multiplication table of 0 .. 15

¨ - for each item

16 16⊤⍵ - take the first 2 digits of hexadecimal encoding

(⎕D,⎕A)[...] - index into "0123456789ABCDEF..."

,' ' - append space

,/ - join each row

↑ - and columnify

Output

00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 02 04 06 08 0A 0C 0E 10 12 14 16 18 1A 1C 1E
00 03 06 09 0C 0F 12 15 18 1B 1E 21 24 27 2A 2D
00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
00 05 0A 0F 14 19 1E 23 28 2D 32 37 3C 41 46 4B
00 06 0C 12 18 1E 24 2A 30 36 3C 42 48 4E 54 5A
00 07 0E 15 1C 23 2A 31 38 3F 46 4D 54 5B 62 69
00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78
00 09 12 1B 24 2D 36 3F 48 51 5A 63 6C 75 7E 87
00 0A 14 1E 28 32 3C 46 50 5A 64 6E 78 82 8C 96
00 0B 16 21 2C 37 42 4D 58 63 6E 79 84 8F 9A A5
00 0C 18 24 30 3C 48 54 60 6C 78 84 90 9C A8 B4
00 0D 1A 27 34 41 4E 5B 68 75 82 8F 9C A9 B6 C3
00 0E 1C 2A 38 46 54 62 70 7E 8C 9A A8 B6 C4 D2
00 0F 1E 2D 3C 4B 5A 69 78 87 96 A5 B4 C3 D2 E1


# Java 8, 9890 79 bytes

v->{for(int i=0;i<256;System.out.printf("%02x%c",i/16*(i++%16),i%16<1?10:32));}


Explanation:

Try it here.

v->{                    // Method with empty unused parameter and no return-type
for(int i=0;          //  Index-integer, starting at 0
i<256;            //  Loop from 0 to 256
System.out.printf(  //   Print with format:
"%02x             //    the lowercase 2-digit hexadecimal representation
%c",         //    + a character
i/16             //     i divided by 16 (integer division in Java truncates)
*(i++%16)        //     multiplied by i modulo-16
//     (and increase i by 1 afterwards with i++)
i%16<1?          //     If i is now a multiple of 16:
10              //      Replace %c with a new-line
:                //     Else:
32)             //      Replace %c with a space instead
);                    //  End of loop
}                       // End of method

• @OlivierGrégoire Oops.. thanks for noticing. Back to 79 bytes (although old 79-byte answer was i%16*(i>>4), but I like i/16 more than i>>4. – Kevin Cruijssen Oct 27 '17 at 11:22

# Julia, 83 75 bytes

r=0:15;[([print(num2hex(i*j)[15:16]," ")for i in r],print('\n'))for j in r]


while($z<256)printf(" "[$x=$z%16]."%02x ",$x*($z++>>4));  Run with -nr or try it online. Note the trailing space in the first line! One byte saved by @gwaugh. • You can -1 byte by eliminating the ! and moving the space to the end of the "%02x ". tio.run/… – gwaugh Feb 7 at 21:13 # QBasic, 73 bytes FOR x=0TO 15 FOR y=0TO 15 ?HEX$(x*y\16);HEX$(x*y MOD 16);" "; NEXT ? NEXT  I golfed a custom procedure for converting to hex digits, before I realized there's a builtin for that. Now my code is shorter and more boring. :^( Original 103-byte code: FOR x=0TO 15 FOR y=0TO 15 p x*y\16 p x*y MOD 16 ?" "; NEXT ? NEXT SUB p(d) ?CHR$(48+d-7*(d>9));
END SUB


# Ink, 169167 161 bytes

VAR r=-1
-(l)
~temp c=0
~r++
{r>15:->END}
-(v)
{h((r*c)/16)}{h(r*c)}
~c++
{c>15:->l}<> ->v
==function h(n)
{n%16-10:
-0:a
-1:b
-2:c
-3:d
-4:e
-5:f
-else:{n%16}
}


Try it online!

# Ungolfed

VAR row=-1                                  // Declare a global variable which keeps track of the current row.
-(line)                                     // A named gather point, which can be jumped to later.

~temp column = 0                            // Declare a local varialbe called column, and set it to 0. Locals use 2 bytes more than globals, but they also reset the value if the line is later reached again.
~row++                                      // Increment the row counter.
{row>15:->END}                              // If we're about to start a 17th row, we terminate the program instead. If not, we continue onwards...

{digit((row*column)/16)}{digit(row*column)} // Calculate the two digits of the number and pass each of them to the digit function defined below to print them.
~column++                                   // Increment the column counter
{column>15:->row}<> ->number                // If we're done with this row we divert to row, to print another row. Otherwise, we concatenate a space to this row and divert to number.

== function digit(n) ==                     // Declare a function which prints a single hex digit.
{n%16-10:                                   // Multi-line conditional - basically a switch statement.
-0:a                                        // If n mod 16 is 10, write an a
-1:b                                        // If it's 11, write a b
-2:c                                        // ...etc...
-3:d
-4:e
-5:f
-else:{n%16}                                // If none of those matched, write n mod 16, as it'll be the same in hex and decimal
}                                           // End of conditional, and also of the function - it doesn't return anything.


Edit: Saved 2 bytes by using stitches instead of knots.
Edit: Saved 3 bytes by tweaking the printing function, and another 3 bytes by rewriting the main logic to use gathers instead of stitches.

• Hello and welcome to PPCG. Would it be possible to provide an online testing environment for ease of verification of your solution? – Jonathan Frech Feb 9 at 1:14

# 05AB1E, 12 bytes

15ÝDδ*16‰hJ»


Try it online.

Explanation:

15Ý           # Create a list in the range [0,15]: [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
D          # Duplicate this list
δ*        # Multiply each pair double vectorized
16‰     # Take the divmod 16 for each
h    # Convert each number to hexadecimal
J   # Join the pairs together
»  # Join each inner list by spaces, and then each string by newlines
# (and output the result implicitly)

• Good idea using ‰ to get the leading 0's. – Emigna Mar 21 at 9:42
• @Emigna Remembered it from some date/time related challenges where leading 0s were mandatory as well (where I used divmod 10). :) Too bad there isn't a 1-byte constant for integers 16 and 32, though.. I use those more often than the 1-bytes 95 and 36, although I guess those were added later, so I kinda understand why these constants are there as 1-byte instead of 2-byte. – Kevin Cruijssen Mar 21 at 9:45
• Yeah, 16 should definitely be a candidate as a 1-byte constant. Should be the most used 2-digit number. I don't think I've used 36 much, if ever. 95 was needed a lot in ascii challenges previously. Although I haven't seen many uses for it recently, I still feel as if it has a place. – Emigna Mar 21 at 9:51
• @Emigna I understand the use of constants 95 and 36, for ASCII and Base challenged respectively. I just feel like there are indeed much better candidates for 1-byte constants than these. These small-number builtins were added later however, after the 2-byte constants already existed, which is probably why it's like it is now. Changing it now would also invalidate quite a few answers.. Ah well. Btw, completely unrelated: do you know how to update the wiki? Some commands are incorrect/missing (like .µ to reset the counter_variable, or .½, .¾, .¼ which should be Å½, Å¾, Å¼ instead). – Kevin Cruijssen Mar 21 at 9:58
• I haven't updated (or even looked at) the wiki, so I'm not 100% certain. I presume you could just fork it and make a pull request as with code updates. @Mr.Xcoder will know for sure as he's done a lot of work on it. – Emigna Mar 21 at 10:04

# Pyth - 24 23 bytes

jjL;c16%L"%02x"*M^U16 2

• Maybe add 256 and then take off the first digit after converting to string? Maybe that's what you're doing. I really don't know Pyth :-P – Esolanging Fruit Dec 17 '16 at 2:24
• @Challenger5 I'm just using Python's format strings – Maltysen Dec 17 '16 at 4:15

# WinDbg, 85 68 bytes

Formatting the output manually:

.for(rip=0;.<100;rip=.+1){.printf"%02x%c",./10*(.%10),a+(f>.%10)*16}


Or using a built-in to format the output, which also outputs some bonus text. Also 68 bytes:

.for(rip=0;.<100;rip=.+1){eb(8<<16)+. .%10*(./10)};db/c10 8<<16 L100


-17 bytes because it turns out the pseudo-register $ip can be read with ., so using that one instead of $t0.

WinDbg's default base is 16 so this looks essentially like it's just code to print the 10x10 decimal multiplication table.

How it works:

.for (r ip=0; .<100; r ip=.+1)        * Loop 256 times
{
.printf "%02x%c", ./10*(.%10),    * Print the result, padded to 2 places
a+(f>.%10)*16                 * Print a space or \n if end of line
}

* OR:

.for (r ip=0; .<100; r ip=.+1)        * Loop 256 times
{
eb (8<<16)+. .%10*(./10)          * Put the result in memory
};
db /c10 8<<16 L100                    * Print the memory as bytes in lines of length 16


Sample output:

0:000> .for(rip=0;.<100;rip=.+1){.printf"%02x%c",./10*(.%10),a+(f>.%10)*16}
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e
00 03 06 09 0c 0f 12 15 18 1b 1e 21 24 27 2a 2d
00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c
00 05 0a 0f 14 19 1e 23 28 2d 32 37 3c 41 46 4b
00 06 0c 12 18 1e 24 2a 30 36 3c 42 48 4e 54 5a
00 07 0e 15 1c 23 2a 31 38 3f 46 4d 54 5b 62 69
00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78
00 09 12 1b 24 2d 36 3f 48 51 5a 63 6c 75 7e 87
00 0a 14 1e 28 32 3c 46 50 5a 64 6e 78 82 8c 96
00 0b 16 21 2c 37 42 4d 58 63 6e 79 84 8f 9a a5
00 0c 18 24 30 3c 48 54 60 6c 78 84 90 9c a8 b4
00 0d 1a 27 34 41 4e 5b 68 75 82 8f 9c a9 b6 c3
00 0e 1c 2a 38 46 54 62 70 7e 8c 9a a8 b6 c4 d2
00 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1

0:000> * OR:

0:000> .for(rip=0;.<100;rip=.+1){eb(8<<16)+. .%10*(./10)};db/c10 8<<16 L100
02000000  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
02000010  00 01 02 03 04 05 06 07-08 09 0a 0b 0c 0d 0e 0f  ................
02000020  00 02 04 06 08 0a 0c 0e-10 12 14 16 18 1a 1c 1e  ................
02000030  00 03 06 09 0c 0f 12 15-18 1b 1e 21 24 27 2a 2d  ...........!$'*- 02000040 00 04 08 0c 10 14 18 1c-20 24 28 2c 30 34 38 3c ........$(,048<
02000050  00 05 0a 0f 14 19 1e 23-28 2d 32 37 3c 41 46 4b  .......#(-27<AFK
02000060  00 06 0c 12 18 1e 24 2a-30 36 3c 42 48 4e 54 5a  ......$*06<BHNTZ 02000070 00 07 0e 15 1c 23 2a 31-38 3f 46 4d 54 5b 62 69 .....#*18?FMT[bi 02000080 00 08 10 18 20 28 30 38-40 48 50 58 60 68 70 78 .... (08@HPXhpx 02000090 00 09 12 1b 24 2d 36 3f-48 51 5a 63 6c 75 7e 87 ....$-6?HQZclu~.
020000a0  00 0a 14 1e 28 32 3c 46-50 5a 64 6e 78 82 8c 96  ....(2<FPZdnx...
020000b0  00 0b 16 21 2c 37 42 4d-58 63 6e 79 84 8f 9a a5  ...!,7BMXcny....
020000c0  00 0c 18 24 30 3c 48 54-60 6c 78 84 90 9c a8 b4  ...$0<HTlx..... 020000d0 00 0d 1a 27 34 41 4e 5b-68 75 82 8f 9c a9 b6 c3 ...'4AN[hu...... 020000e0 00 0e 1c 2a 38 46 54 62-70 7e 8c 9a a8 b6 c4 d2 ...*8FTbp~...... 020000f0 00 0f 1e 2d 3c 4b 5a 69-78 87 96 a5 b4 c3 d2 e1 ...-<KZix.......  # Scala, 56 bytes for(x<-0 to 15){for(y<-0 to 15)printf("%02x ",x*y);println}  Ungolfed: for(x<-0 to 15){ for(y←0 to 15) printf("%02x ",x*y); println }  Explanation: for(x<-0 to 15){ //count from 0 to 15 using the variable x for(y←0 to 15) //count from 0 to 15 using the variable y printf("%02x ",x*y); //print x*y as a hex string with leading zeros and a width of 2 characters println //print a newline }  # Common Lisp, 887069 63 bytes (#1=dotimes(j 16)(#1#(k 16)(format t"~2,'0x "(* k j)))(terpri))  Using idea from here ### A bit of explanation ~2,'0x ;display in hexadecimal, padding with minimum two digits, padding symbol is 0  # Proton, 60 bytes x=0;eval("print(' '.join('%02x'%(x*y)for y:0..16));x++;"*16)  Try it online! # Excel VBA, 58 54 Bytes Anonymous VBE immediate window function that takes no input and outputs the FxF hex multiplication table to the range [A1:P16] [A1:P16]="=Right(0&Dec2Hex((Row()-1)*(Column()-1)),2)"  # q/kdb+, 46 26 bytes Solution: -1" "sv'($)4h$x*/:x:(!)16;  Example: q)-1" "sv'($)4h$x*/:x:(!)16; 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 00 02 04 06 08 0a 0c 0e 10 12 14 16 18 1a 1c 1e 00 03 06 09 0c 0f 12 15 18 1b 1e 21 24 27 2a 2d 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 00 05 0a 0f 14 19 1e 23 28 2d 32 37 3c 41 46 4b 00 06 0c 12 18 1e 24 2a 30 36 3c 42 48 4e 54 5a 00 07 0e 15 1c 23 2a 31 38 3f 46 4d 54 5b 62 69 00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78 00 09 12 1b 24 2d 36 3f 48 51 5a 63 6c 75 7e 87 00 0a 14 1e 28 32 3c 46 50 5a 64 6e 78 82 8c 96 00 0b 16 21 2c 37 42 4d 58 63 6e 79 84 8f 9a a5 00 0c 18 24 30 3c 48 54 60 6c 78 84 90 9c a8 b4 00 0d 1a 27 34 41 4e 5b 68 75 82 8f 9c a9 b6 c3 00 0e 1c 2a 38 46 54 62 70 7e 8c 9a a8 b6 c4 d2 00 0f 1e 2d 3c 4b 5a 69 78 87 96 a5 b4 c3 d2 e1  Explanation: -1" "sv'string 4h$x*/:x:til 16; / ungolfed solution
til 16  / range 0..15
x:        / save in variable x
x*/:          / x multiplied by each-right (generate 0..15*0..15)
4h$/ cast result to byte array (0x00...) string / convert byte array to string " "sv' / join (sv) each (') with space (" ") -1 ; / write to stdout and swallow return value  Notes: • -20 byte saving by complete re-write. # J, 22 bytes echo,.3{."1 hfd*/~i.16  Try it online! VBA (Excel), 45 Bytes By using VBA Immediate Window. [A1:P16]="=DEC2HEX((row()-1)*(column()-1),2)"  # Tcl, 98 bytes time {incr i set j 0 time {puts -nonewline [format %02x\ [expr ($i-1)*$j]] incr j} 16 puts ""} 16  Try it online! # Tcl, 102 bytes set i 0 time {set j 0 time {puts -nonewline [format %02x\ [expr$i*j]] incr j} 16 puts "" incr i} 16  Try it online! Will golf it more later! # Jq 1.5, 105 bytes def h:[("0123456789abcdef"/"")[.[]]]|add;[range(16)*range(16)|[(./16|floor),.%16]|h]|_nwise(16)|join(" ")  Expanded (jq has no "%x" formatting so we roll our own) def tohex: # convert [x,y] to hex string "xy" [("0123456789abcdef"/"")[.[]]] | add; [ range(16)*range(16) # generate values | [(./16|floor), .%16] # convert to [x,y] digits base 16 | tohex # convert to hex string ] | _nwise(16) # split into subarrays of length 16 | join(" ") # convert subarrays to strings  Try it online! # Forth (gforth), 65 bytes : f 16. do cr 16. do i j * 16 /mod hex 1 .r . decimal loop loop ;  Try it online! ### Explanation Nested loop from 0 to 15. Each Iteration: • multiply row and column numbers to get result • split into first and second digit (first digit will be 0 if result < 16) • set base to 16 (hexadecimal) • print first digit with no space • print second digit with space • set base to 10 (decimal) ### Code Explanation : f \ start new word definition 16. do \ outer loop from 0 to 15 cr \ output newline 16. do \ inner loop from 0 to 15 i j * \ multiply loop indexes 16 /mod \ get quotient and remainder of dividing by 16 hex \ set base to 16 1 .r \ print quotient (equivalent to first digit) right-aligned in space of 1 (no space) . \ print second digit (with space) decimal \ set base back to 10 (decimal) loop \ end inner loop loop \ end outer loop ; \ end word definition  # C# (Visual C# Interactive Compiler), 67 bytes for(int i=0;i<256;)Write("{(i%16<1?"\n":"")} {i/16*(i++%16):X2}");


Try it online!

# Mouse-2002, 58 bytes

8&WSIZE (qx.-^x.0y:(y.q<^y.x.y.*&!HEX " "y.1+y:)"!"x.1+x:)


Try it online!

# Pyth, 24 bytes

V16FZU16p+%"%02x"*ZNd)pb


Try it online!

Might post an explanation or ungolfed version later.

# APL(NARS), 42 chars, 84 bytes

{{(⎕D,⎕A)[1+16∣(⌊⍵÷16),⍵]}¨×/¨m∘.,m←0,⍳15}


I copy something from others... ×/¨m∘.,m←0,⍳15 would build the multiplication table of 0,⍳15; the function {(⎕D,⎕A)[1+16∣(⌊⍵÷16),⍵]} convert each number in the multiplication table in hex for only 2 digits.

 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00 02 04 06 08 0A 0C 0E 10 12 14 16 18 1A 1C 1E
00 03 06 09 0C 0F 12 15 18 1B 1E 21 24 27 2A 2D
00 04 08 0C 10 14 18 1C 20 24 28 2C 30 34 38 3C
00 05 0A 0F 14 19 1E 23 28 2D 32 37 3C 41 46 4B
00 06 0C 12 18 1E 24 2A 30 36 3C 42 48 4E 54 5A
00 07 0E 15 1C 23 2A 31 38 3F 46 4D 54 5B 62 69
00 08 10 18 20 28 30 38 40 48 50 58 60 68 70 78
00 09 12 1B 24 2D 36 3F 48 51 5A 63 6C 75 7E 87
00 0A 14 1E 28 32 3C 46 50 5A 64 6E 78 82 8C 96
00 0B 16 21 2C 37 42 4D 58 63 6E 79 84 8F 9A A5
00 0C 18 24 30 3C 48 54 60 6C 78 84 90 9C A8 B4
00 0D 1A 27 34 41 4E 5B 68 75 82 8F 9C A9 B6 C3
00 0E 1C 2A 38 46 54 62 70 7E 8C 9A A8 B6 C4 D2
00 0F 1E 2D 3C 4B 5A 69 78 87 96 A5 B4 C3 D2 E1


I see how using functions and ¨ problems are break in simple problems...

## Perl 6, 49 36 bytes

say ($_ <<*<<^16).fmt("%02x")for ^16  Old solution: for ^16 ->\a {printf "%02x ",a*$_ for ^16;say ""}


# Charcoal, 16 15 bytes

Ｅ¹⁶⭆¹⁶﹪%02x ×ιλ


Try it online! Link is to verbose version of code.

Alternative 16-byter using automatic grid output of Wolfram lists: ▷LＥ¹⁶Ｅ¹⁶﹪%02x×κμ

### Explanation

Ｅ¹⁶                      Map for i from 0 to 15 (with k as index variable, but here it's the same as i)
⭆¹⁶                  Map for l from 0 to 15 (with m as index variable), then join with "" into a string
﹪                Modulo (used for Python's string format here)
%02x            Input formatted (%), padded with zeros (0) to length two (2)
as a hexadecimal number (x), with a space ( ) at the end
×ιλ        i * l


# MathGolf, 16 bytes

☻r■mÉε*¢0═ uM∞/n


Try it online!

## Explanation

It might be shorter to do it with a loop, I'll have to try that.

☻                  push 16
r                 range(0, n)
■                cartesian product with itself
mÉ              explicit map using next 3 operators
ε*            reduce list by multiplication