基本情報技術者試験 ファイルの内容を16進数で表示する

令和元年度秋期の基本情報技術者試験の午後問題の問9の「ファイルの内容を16進数で表示する」プログラムを実行しました。

#include <stdio.h>
#include <stdlib.h>

#define WIDTH 60
#define MASKCHR '.'

void dump(char *filename, long from, long to) {
  FILE *infile;
  int chr, pos = 0;
  long cnt = 0;
  char tbl_char[256], buf_char[WIDTH + 1];
  char tbl_high[256], buf_high[WIDTH + 1];
  char tbl_low[256], buf_low[WIDTH + 1];
  char hex[] = "0123456789ABCDEF";

  for (chr = 0x00; chr <= 0xFF; chr++) {
    if ((0x20 <= chr) && (chr <= 0x7E))
      tbl_char[chr] = chr;
    else
      tbl_char[chr] = MASKCHR;
    tbl_high[chr] = hex[chr >> 4];
    tbl_low[chr] = hex[chr & 0x0F];
  }

  buf_char[WIDTH] = buf_high[WIDTH] = buf_low[WIDTH] = '\0';
  infile = fopen(filename, "rb");
  while ( ((chr = fgetc(infile)) != EOF) && ((to < 0) || (cnt <= to)) ) {
    cnt++;
    if (cnt > from) {
      buf_char[pos] = tbl_char[chr];
      buf_high[pos] = tbl_high[chr];
      buf_low[pos] = tbl_low[chr];
      pos++;
      if (pos == WIDTH) {
        printf("%10ld  %s\n%12s%s\n%12s%s\n\n",
               cnt - WIDTH, buf_char, " ", buf_high, " ", buf_low);
        pos = 0;
      }
    }
  }
  if (pos > 0) {
    buf_char[pos] = buf_high[pos] = buf_low[pos] = '\0';
    printf("%10ld  %s\n%12s%s\n%12s%s\n\n",
           cnt - pos, buf_char, " ", buf_high, " ", buf_low);
  }
  if (chr == EOF)
    printf("END OF DATA ... %ld byte(s)\n", cnt - from);
  else
    printf("END OF DUMP ... %ld byte(s)\n", cnt - from);

  fclose(infile);
}

int main(int argc, char *argv[]) {
  dump(argv[1], atol(argv[2]), atol(argv[3]));

  return 0;
}
$ cat ascii.txt 
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

$ od -tx1 ascii.txt 
000000 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
000010 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
000020 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
000030 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
000040 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
000050 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 0a
000060

$ ./hexdump ascii.txt 0 -1
         0   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[
            222222222222222233333333333333334444444444444444555555555555
            0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789AB

        60  \]^_`abcdefghijklmnopqrstuvwxyz{|}~.
            555566666666666666667777777777777770
            CDEF0123456789ABCDEF0123456789ABCDEA

END OF DATA ... 96 byte(s)

Pythonでアスキーコード0x20から0X7Eの文字をファイルに出力する

文字から文字コードを取得する

>>> ord('a')
97
>>> ord('z')
122
>>> ord('A')
65
>>> ord('Z')
90
>>> ord('0')
48
>>> ord('9')
57
>>> ord(' ')
32
>>> ord('~')
126

16進数で表示するなら

>>> hex(ord('a'))
'0x61'
>>> hex(ord(' '))
'0x20'
>>> hex(ord('~'))
'0x7e'

文字コードを文字に変換する

>>> chr(97)
'a'
>>> chr(0x61)
'a'
>>> chr(0x20)
' '
>>> chr(0x7e)
'~'

アスキーコード0x20から0X7Eの文字をファイルに出力する

f = open('ascii.txt', 'w')
for code in range(0x20, 0x7e + 1):
    f.write(chr(code))
f.close()
$ cat ascii.txt 
 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

$ od -tx1 ascii.txt 
0000000 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
0000020 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
0000040 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
0000060 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
0000100 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
0000120 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e

基本情報技術者試験 乱数 Python randint

Pythonで0以上9以下の整数の乱数を生成する

>>> import random
>>> random.randint(0, 9)
3

A = random.randint(0, 9)
B = random.randint(0, 9)
として、AとBが等しくとなる確率を求める。

import random

total = 10000
cnt = 0

for _ in range(0, total):
    if random.randint(0, 9) == random.randint(0, 9):
        cnt += 1

print(cnt / total)

Pythonで正規分布のグラフを描く

正規分布のグラフは平均値を中心にして左右対称になるそうです。

import numpy as np
from scipy.stats import norm #normは正規分布
import matplotlib.pyplot as plt

X = np.arange(0, 100, 0.1)

#pdfは確率密度関数
#平均:60, 標準偏差:10
Y = norm.pdf(X, 60, 10)

#グラフの表示
plt.plot(X, Y)
plt.show()

f:id:collatz:20210411151405p:plain

C 文字列の分割(strtok) GDBで観察

"12 34 56"というスペースで区切られた文字列を "12", "34", "56" に分割するプログラム
strtokを繰り返し実行することで、順番に"12", "34", "56"を取得できる。

1回目のstrtokの実行で、
strは"12 34 56"から"12\034 56"に変更される(1番目のスペースが\0に置き換わる)。
そして、strtokは、文字列"12\0"の先頭のポインタを返す。

2回目のstrtokの実行で、
strは"12\034 56"から"12\034\056"に変更される(2番目のスペースが\0に置き換わる)。
そして、strtokは、文字列"34\0"の先頭のポインタを返す。

3回目のstrtokの実行で、
strは変更されない。
そして、strtokは、文字列"56\0"の先頭のポインタを返す。

#include <stdio.h>
#include <string.h>

int main(void) {
  char str[] = "12 34 56";
  char *tp;

  tp = strtok(str, " ");
  puts(tp);
  while (tp != NULL) {
    tp = strtok(NULL, " ");
    if (tp != NULL) puts(tp);
  }

  return 0;
}
(gdb) break main
Breakpoint 1 at 0x114d: file strtok_sample.c, line 5.
(gdb) run
Breakpoint 1, main () at strtok_sample.c:5
5         char str[] = "12 34 56";
(gdb) next
8         tp = strtok(str, " ");
(gdb) x/s str
0x7fffffffdedf: "12 34 56"
(gdb) x/9xb str
0x7fffffffdedf: 0x31    0x32    0x20    0x33    0x34    0x20    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) next
9         puts(tp);
(gdb) x/s str
0x7fffffffdedf: "12"
(gdb) x/9xb str
0x7fffffffdedf: 0x31    0x32    0x00    0x33    0x34    0x20    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) x/s tp
0x7fffffffdedf: "12"
(gdb) x/9xb tp
0x7fffffffdedf: 0x31    0x32    0x00    0x33    0x34    0x20    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) next
12
10        while (tp != NULL) {
(gdb) next
11          tp = strtok(NULL, " ");
(gdb) next
12          if (tp != NULL) puts(tp);
(gdb) x/s str
0x7fffffffdedf: "12"
(gdb) x/9xb str
0x7fffffffdedf: 0x31    0x32    0x00    0x33    0x34    0x00    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) x/s tp
0x7fffffffdee2: "34"
(gdb) x/9xb tp
0x7fffffffdee2: 0x33    0x34    0x00    0x35    0x36    0x00    0xe2    0xde
0x7fffffffdeea: 0xff
(gdb) next
34
10        while (tp != NULL) {
(gdb) next
11          tp = strtok(NULL, " ");
(gdb) next
12          if (tp != NULL) puts(tp);
(gdb) x/s str
0x7fffffffdedf: "12"
(gdb) x/9xb str
0x7fffffffdedf: 0x31    0x32    0x00    0x33    0x34    0x00    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) x/s tp
0x7fffffffdee5: "56"
(gdb) x/9xb tp
0x7fffffffdee5: 0x35    0x36    0x00    0xe5    0xde    0xff    0xff    0xff
0x7fffffffdeed: 0x7f
(gdb) next
56
10        while (tp != NULL) {
(gdb) next
11          tp = strtok(NULL, " ");
(gdb) next
12          if (tp != NULL) puts(tp);
(gdb) print tp
$1 = 0x0
(gdb) x/9xb str
0x7fffffffdedf: 0x31    0x32    0x00    0x33    0x34    0x00    0x35    0x36
0x7fffffffdee7: 0x00
(gdb) next
10        while (tp != NULL) {
(gdb) next
15        return 0;

PythonのNumpyで乱数を生成する

>>> import numpy as np

0.0から1.0までの乱数を1つ生成する
>>> np.random.rand()
0.5663322709892451
>>> np.random.rand()
0.4082004363131747
>>> type(np.random.rand())
<class 'float'>

0.0から1.0までの乱数を3つ生成する
>>> np.random.rand(3)
array([0.22635023, 0.81082541, 0.77187752])
>>> np.random.rand(3)
array([0.28170496, 0.58370712, 0.36195884])
>>> type(np.random.rand(3))
<class 'numpy.ndarray'>

平均:50, 標準偏差:10 の正規分布に従う乱数を5個生成する
>>> np.random.normal(60, 10, 5)
array([53.76061443, 80.28227809, 53.64735196, 61.27652602, 40.84847383])

基本情報技術者試験 関数の極限値をPythonのSympyで求める

 \displaystyle f(t)=\frac{1}{t+1},  \displaystyle g(t)=\frac{1}{t^2-t}であるとき,  \displaystyle \lim_{t \to \infty} \frac{g(t)}{f(t)}を求める

from sympy import oo, limit, Symbol, plot

t = Symbol('t')


f = 1 / (t + 1)
g = 1 / (t**2 - t)

print(limit(g / f, t, +oo))
plot(g / f, (t, 10, 1000))

f:id:collatz:20210408164255p:plain