2022/09,江端さんの技術メモ

Goにはクラスの概念がありません。

C++で作ってきたプログラムをGoに移植しているのですが、クラスで記載した部分を上手いこと使い回したくても、それができなくて困っていました。

で、

GO言語でクラスっぽいことをする

という記事を見つけて、これを使って勉強させて頂いていますが、困ったことがあります。

プログラムの中の変数の意味が分からない ―― HPとか、MPとか、APは、アニメ(多分ゲームも?)の中では頻繁に登場するのですが、私は何の略号か分からなかったので、サンプルプログラムの意味が読み解けませんでした。

そこで、上記記事に記載されていたプログラムに、そのまま、私の為に、コメントを付けさせて頂きました。

package main

import (
	"fmt"
)

const line = "--------------------"

func main() {
	wiz := newWizard("魔法少女", 10, 10, 5)
	war := newWarrior("+‡†狂戦士†‡+", 10, 15, 30)

	fmt.Println(wiz.hello())
	fmt.Println(war.hello())

	fmt.Println(line)
	fmt.Println(wiz.attack())
	fmt.Println(war.attack())

	fmt.Println(line)
	fmt.Println(wiz.magic())
	fmt.Println(war.attack())
}

type human struct { // "人間"という基底クラス
	name string
	hp   int
	ap   int
}

func (h *human) init(name string, hp, ap int) { // "人間"という基底クラスのコンストラクタ(3つの初期値を入れていることに注意))
	h.name = name // 名前
	h.hp = hp     // ヒットポイント: ゲームにおいてキャラの体力や生命力を示すステータスの一つ
	h.ap = ap     // アタックポイント: ゲームにおいてキャラの行動力などを示すステータスの一つ
}

func (h *human) hello() string { // "人間"という基底クラスのメソッド1
	return fmt.Sprintf("こんにちは、私は%sです。", h.name)
}

func (h *human) attack() string { // "人間"という基底クラスのメソッド2
	return fmt.Sprintf("%sの攻撃!%dのダメージ!", h.name, h.ap)
}

type wizard struct { // "魔法使い"というクラス
	human     // "人間の属性"を手動挿入
	mp    int // マジックポイント: ゲームにおいてキャラの魔法や呪文を使う力を示すステータスの一つ
}

func newWizard(name string, hp, ap, mp int) *wizard { // "魔法使い"クラスのコンストラクタ(4つの初期値を入れていることに注意))
	w := new(wizard)     // "魔法使い"の実体生成
	w.init(name, hp, ap) // "基底クラス"の属性値の設定
	w.mp = mp            // 新しい属性値の設定
	return w
}

func (w *wizard) magic() string {
	if w.mp <= 0 {
		return fmt.Sprintf("%sは力がでない", w.name)
	}
	w.mp -= 1
	return fmt.Sprintf("%sは魔法を使った!30のダメージ!", w.name)
}

type warrior struct {
	human // "人間の属性"のみを手動挿入
}

func newWarrior(name string, hp, ap, mp int) *warrior {
	w := new(warrior)
	w.init(name, hp, ap)
	// mpは使わない? Warrior(戦士)は、マジックポイントを持たないものなの?
	return w
}

func (w *warrior) attack() string {
	return fmt.Sprintf("%sの攻撃!%dのダメージ!", w.name, w.ap*2)
}

なるほど、変数の意味が分かれば、プログラムの趣旨が読み取れました ―― 加えて、アニメの中の台詞も理解できるようになり、一石二鳥でした。
ゲームをやっている人であれば、「今更なこと」だったんだろうな、と思っています。


とほほのGo言語入門 構造体(struct)

を読んでいたら、構造体(struct)でクラスと同じことができることが分かりました。

また、インタフェース(interface)を使えばポリモーフィズムもできるみたいでした。

しかも、コンストラクタとかデストラクタとか、面倒なものもを入れていないという点も好印象です。

Golangの設計者、よく分かってるじゃん!』と、絶賛賞賛中です。

2022/09,江端さんの技術メモ

Golangで "OpenError: sql: unknown driver "postgres" (forgotten import?) "で悩まされていました。

よく分かりませんが、"go.mod", "go.sum"とかをいじることなく

(1)ターミナルから、

go get github.com/lib/pq

として、

(2)import に

import (
   //  色々
    _ "github.com/lib/pq" // ←これを追記
)

で動きました。

2022/09,江端さんの技術メモ

golangを使った、postgresqlのinsertの方法

/*

こんな感じで、DBとTableを作りました

create database agent_db;

create table LocMessage(
	ID     int,
	Lat    double precision,
	Lng    double precision,
	TYPE   varchar(10),
	POPUP  int,
	RealId int,
	PersonState      int,
	BikeState        int,
	StartStationLat  double precision,
	StartStationLng  double precision,
	GoalStationLat   double precision,
	GoalStationLng   double precision,
	StartStationName varchar(40),
	GoalStationName  varchar(40)
);

ちなみに、全部小文字になるみたいですねえ。
agent_db=# select * from locmessage;
 id |  lat   |  lng  |   type   | popup | realid | personstate | bikestate | startstationlat | startstationlng | goalstationlat | goalstationlng | startstationname | goalstationname
----+--------+-------+----------+-------+--------+-------------+-----------+-----------------+-----------------+----------------+----------------+------------------+-----------------

*/

package main

import (
	"database/sql"
	"log"

	_ "github.com/lib/pq"
)

func main() {

	db, err := sql.Open("postgres",
		"user=postgres password=password host=localhost port=15432 dbname=agent_db sslmode=disable")
	if err != nil {
		log.Fatal("OpenError: ", err)
	}
	defer db.Close()

	//_, err = db.Exec("insert into locmessage(id,lat,lng,type,popup,realid,startstationlng ) VALUES(1, 139.0, 38.0, 'PERSON',1,1,222.222);")
	// _, err = db.Exec("insert into locmessage(id,lat) VALUES(a, b);")
	//ins, err := db.Prepare("insert into locmessage(id,lat,lng,type,popup,realid,startstationlng ) VALUES(?,?,?,?,?,?,?)")
	ins, err := db.Prepare("insert into locmessage(id,lat,lng,type,popup,realid,startstationlng ) VALUES($1,$2,$3,$4,$5,$6,$7)")
	if err != nil {
		log.Fatal("db.Exec Error: ", err)
	}

	a := 1
	b := 139.02
	c := 38.02
	dd := "Tomoichi"
	e := 1
	f := 1
	g := 333.333

	//ins.Exec("1", "139.0", "38.0", "BIKE", "1", "1", "222.222")
	//ins.Exec(1, 139.01, 38.01, "BIKE", 1, 1, 222.222)
	//ins.Exec(1, 139.0, 38.0, 1, 1, 1, 222.222)
	ins.Exec(a, b, c, dd, e, f, g)

}

とりあえず、これでデータベースの書き込みはできるみたい。

2022/09,江端さんの技術メモ

(Step.1) vscodeでmarkdownを使って本文を書いて、PDF(A4サイズ)にする

vscodeに以下の拡張機能は絶対に入れる

Visual Studio CodeのMarkdown編集から、いきなりPDFを作ったり、目次を追加したりできる件

vscodeでMarkdownを使って文章を書いている時、図面のコピペを文書の中にサクっと入れることができるアドイン "Paste Image"

(Step.1) SAIやPowerPointを使って、表紙と裏表紙を描いて、PDF(A4サイズ)にする

(Step.3) ConcatPDF(GUI)を使って、上記をマージして、書籍の名前のファイル名に保存する

(Step.4) 「江端さんの本屋さん」へアップロードする

新しいファイルをドラッグして、完了

ちなみに、以前のバージョンを購入して頂いた方は、最新版を無料で御提供する旨を、メッセージに追加(現在は、『メールでご連絡下さい』としているが、自動的にやる方法があるのか? 現在調査中)。

 

2022/09,江端さんの技術メモ

最近、スペルチェックをvscodeにやらせていて、emacsでのリロードを何度もやっているのだけど、これが中々に面倒で、これを一発でできないものか、色々調べた結果です。

方針: 面倒なので、".emacs" だけの記載で終了したい
操作:<F5>押すだけ
判ったこと: ".emacs"の最後に追記すると動かない(私の環境だけかもしれないが) → ".emacs"の真ん中あたりに突っ込んだ。

;;;; バッファを一発でリロードする (.emacsの最後に記載したら動かなかったので、真ん中くらいに移動)

(defun revert-buffer-no-confirm (&optional force-reverting)
  (interactive "P")
  ;;(message "force-reverting value is %s" force-reverting)
  (if (or force-reverting (not (buffer-modified-p)))
      (revert-buffer :ignore-auto :noconfirm)
    (error "The buffer has been modified")))

;; reload buffer
(global-set-key (kbd "<f5>") 'revert-buffer-no-confirm)
;;(global-set-key "\C-c\C-r" 'revert-buffer-no-confirm)
;;(global-set-key "\M-r" 'revert-buffer-no-confirm)
;(global-set-key "\C-c\C-m" 'revert-buffer-no-confirm)

2022/09,江端さんの技術メモ

こっちはPythonで書いたファジィ(Fuzzy)推論コードです。



# -*- coding: utf-8 -*-
# 上記の一行がないと、コメント分の和文も全部エラーになる 

# シンプルファジィ推論プログラム ver0.0 2015年12月15日
# シンプルファジィ推論プログラム ver0.1 2023年04月20日 print文の仕様変更対応

# メンバーシップ関数は、前件部、後件部ともに3つに固定した単純なもの
# 推論方式は、単純なmin-max重心法のみ



class condition_MF:
    
    center = 0
    width =  100
    PV ="LESS"

    def __init__(self, center, width, PV):
        self.center = center
        self.width = width
        self.PV = PV

    # x,yは、メンバーシップ関数上の座標を示す
    def func(self, x):
        if (self.PV == "LESS"):
            if (x <= self.center - self.width):
                y = 1.0
            elif (x <= self.center):
                y = - 1.0 / self.width * (x - self.center)
            else:
                y = 0.0        
        elif (self.PV == "ZERO"):
            if (x <= self.center - self.width):
                y = 0.0
            elif (x <= self.center):
                y = 1.0 / self.width * (x - self.center) + 1.0
            elif (x <= self.center + self.width):
                y = -1.0 / self.width * (x - self.center) + 1.0
            else:
                y = 0.0       
        elif (self.PV == "MORE"):
            if (x <= self.center):
                y = 0.0
            elif (x <= self.center + self.width):
                y = 1.0 / self.width * (x - self.center)
            else:
                y = 1.0
        
        return y

class action_MF:
    center = 0 # 値はダミー
    width =  100 # 値はダミー
    PV ="ZERO" # 値はダミー
    y = 0.0 # 最大値で更新されていく
    x = 0.0 # 値はダミー

    def __init__(self, center, width, PV):
        self.center = center
        self.width = width
        self.PV = PV

        if (self.PV == "LESS"):
            self.x = self.center - self.width
        elif (self.PV == "ZERO"):
            self.x = self.center
        elif (self.PV == "MORE"):
            self.x = self.center + self.width
        else:
            print ("error")

    # yを最大値で更新していく
    def func_Max(self,b):
        self.y = max(b, self.y)

    # X座標を返す
    def func_X(self):
        return self.x

    # (最大値で更新された、最後の)Y座標を返す
    def func_Y(self):
        return self.y

temp_High = condition_MF(20.0, 10.0, "MORE") # 温度が高い
temp_Middle = condition_MF(20.0, 10.0, "ZERO") #温度が普通
temp_Low = condition_MF(20.0, 10.0, "LESS")# 温度が低い

humi_High = condition_MF(50.0, 20.0, "MORE") # 湿度が高い
humi_Middle = condition_MF(50.0, 20.0, "ZERO") #湿度が普通
humi_Low = condition_MF(50.0, 20.0, "LESS")# 湿度が低い

switch_High = action_MF(0.0, 1.0, "MORE") # エアコンの温度設定を上げる("+1"にする)
switch_Middle = action_MF(0.0, 1.0, "ZERO")# エアコンの温度設定に何もしない("0"にする)
switch_Low = action_MF(0.0, 1.0, "LESS") # エアコンの温度設定を下げる("-1"にする)


# 入力値(温度27度、湿度57%)
t = 35.0
h = 80.0

# (1)「もし、温度が高くて、湿度が高ければ、エアコンの温度設定を下げる」
a1 = min(temp_High.func(t),humi_High.func(h))
print (a1)
switch_Low.func_Max(a1) 

print ("Low") 
print (switch_Low.func_Y()) 

# (2)「もし、温度が普通で、湿度が高ければ、何もしない」
a2 = min(temp_Middle.func(t),humi_High.func(h))
switch_Middle.func_Max(a2) 

print ("Middle") 
print (switch_Middle.func_Y()) 

# (3)「もし、温度が高くて、湿度が普通なら、エアコンの温度設定を下げる」

a3 = min(temp_High.func(t),humi_Middle.func(h))
switch_Low.func_Max(a3) 
print ("Low") 
print (switch_Low.func_Y()) 

# (4)「もし、温度が低くて、湿度が低ければ、エアコンの温度設定を上げる」
a4 = min(temp_Middle.func(t),humi_Low.func(h))
switch_High.func_Max(a4) 
print ("High") 
print (switch_High.func_Y()) 

# (5)(追加)もし温度が普通で、湿度が普通なら、何もしない
a5 = min(temp_Middle.func(t),humi_Middle.func(h))
switch_Middle.func_Max(a5) 
print ("Middle") 
print (switch_Middle.func_Y()) 

# 重心値を求める
# (ルールが推論空間を網羅していないと、ゼロ割が発生することがあるので注意)

reasoning =  (switch_High.func_X() * switch_High.func_Y()  + switch_Middle.func_X() * 
switch_Middle.func_Y()  + switch_Low.func_X() * switch_Low.func_Y()) / (switch_High.func_Y()  + switch_Middle.func_Y()  + switch_Low.func_Y())

print ("\n reasoning")
print (reasoning)

元ネタはこちら(クリックするとページに飛びます)。

ファジィ推論

2022/09,江端さんの技術メモ

Go言語を使った自作のファジィ(Fuzzy)推論コードを探していたのですが、見つけることができずにちょっとショックを受けております。

というか、Go言語どころか、C言語でも見つけられなかった(いや、あるはずだ)ので、今、PCの中探して見つかったものをアップしておきます。

毎回スクラッチから作るのも迂遠なので。

↓のコードですが、こちらのコラムで使ったものだと思います。

/*
  このプログラムをfuzzy.cpp"という名前で保存して、
  gcc -g fuzzy.cpp -o fuzzy
  でコンパイルして下さい。
*/



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


// 共通関数
double max(double a){
    return a;
}

double max(double a, double b){
    if (a > b) 
        return a;
    else 
        return b;
};

double max(double a, double b, double c ){
    return max(max(a,b), max(b,c)); 
};

double max(double a, double b, double c, double d ){
    return max(max(a,b,c), d); 
};

double min(double a){
    return a;
}

double min(double a, double b){
    if (b > a) 
        return a;
    else 
        return b;
};

double min(double a, double b, double c ){
    return min(min(a,b), min(b,c)); 
};

double min(double a, double b, double c, double d ){
    return min(min(a,b,c), d); 
};


// ファジィ表現
typedef enum scale {LESSLESS, LESS, ZERO, MORE, MOREMORE} SCALE;

// 前件部メンバーシップ関数(山3つ)クラス
class condition_MF3
{
private:
    double center;
    double width;
    SCALE express;
   
public:
    condition_MF3(double _center, double _witdth, SCALE _express){
        center = _center;
        width = _witdth;
        express = _express;

        // 使用できないファジィ表現を使った場合は止める        
        if ((express == LESSLESS) || (express == MOREMORE)){
            printf("wrong expression used \n");
            exit(0);
        }

    };
    double func(double _x);
};

double condition_MF3::func(double _x)
{
// x,yは、メンバーシップ関数上の座標を示す
    double x = _x;
    double y = 0.0; // yの値は、必ず0以上1以下になる

    if (express == LESS){
        if (x <= center - width){
            y = 1.0;
        }
        else if (x <= center){
            y = - 1.0 / width * (x - center);
        }
        else{
            y = 0.0;
        }
    }
    else if (express == ZERO){
        if (x <= center - width){
            y = 0.0;
        }
        else if (x <= center){
            y = 1.0 / width * (x - center) + 1.0;
        }
        else if (x <= center + width){
            y = -1.0 / width * (x - center) + 1.0;
        }
        else{
            y = 0.0;
        }
    }
    else if (express == MORE){
        if (x <= center){
            y = 0.0;
        }
        else if (x <= center + width){
            y = 1.0 / width * (x - center);
        }
        else{
            y = 1.0;
        }
    }
    else {
        printf("wrong expression\n");
        exit(1);
    }

    return y;
};

// 前件部メンバーシップ関数(山5つ)クラス
class condition_MF5
{
private:
    double center;
    double width;
    SCALE express;
   
public:
    condition_MF5(double _center, double _witdth, SCALE _express){
        center = _center;
        width = _witdth;
        express = _express;
    };
    double func(double _x);
};


double condition_MF5::func(double _x)
{
// x,yは、メンバーシップ関数上の座標を示す
    double x = _x;
    double y = 0.0; // yの値は、必ず0以上1以下になる

    if (express == LESSLESS){
        if (x <= center - 2.0 * width){
            y = 1.0;
        }
        else if (x <= center - width){
            y = - 1.0 / width * (x - (center - 2.0 * width)) + 1.0;
        }
        else{
            y = 0.0;
        }
    }
    else if (express == LESS){
        if (x <= center - 2.0 * width){
            y = 0.0;
        }
        else if (x <= center - width){
            y = 1.0 / width * (x - (center - width)) + 1.0;
        }
        else if (x <= center){
            y = -1.0 / width * (x - (center - width)) + 1.0; 
        }
        else{
            y = 0.0;
        }
    }
    else if (express == ZERO){
        if (x <= center - width){
            y = 0.0;
        }
        else if (x <= center){
            y = 1.0 / width * (x - center) + 1.0;
        }
        else if (x <= center + width){
            y = -1.0 / width * (x - center) + 1.0;
        }
        else{
            y = 0.0;
        }
    }
    else if (express == MORE){
        if (x <= center){
            y = 0.0;
        }
        else if (x <= center + width){
            y = 1.0 / width * (x - (center + width)) + 1.0;
        }
        else if (x <= center + 2.0 * width){
            y = -1.0 / width * (x - (center + width)) + 1.0; 
        }
        else{
            y = 0.0;
        }
    }
    else if (express == MOREMORE){
        if (x <= center + width){
            y = 0.0;
        }
        else if (x <= center + 2.0 * width){
            y = 1.0 / width * (x - (center + 2.0 * width)) + 1.0;
        }
        else{
            y = 1.0;
        }
    }

    return y;
};

// 後件部メンバーシップ関数(山3つ)クラス  
class action_MF3
{
private:
    double center;
    double width;
    SCALE express;

    double x;
    double y;

public:
    action_MF3(double _center, double _witdth, SCALE _express){

        y = 0.0; // yの値は、必ず0以上1以下になる
       
        center = _center;
        width = _witdth;
        express = _express;
        
        if (express == LESS){
            x = center - width;
        }
        else if (express == ZERO){
            x = center;
        }
        else if (express == MORE){
            x = center + width;
        }
        else{
            printf("wrong scale expression\n");
            exit(0);
        }
    };
    
    void func_Max(double b){
        y = max(b, y);
    };
    
// X座標を返す
    double func_X(void){
        return x;
    };
    
    // (最大値で更新された、最後の)Y座標を返す
    double func_Y(){
        return y;
    };

};

// 後件部メンバーシップ関数(山5つ)クラス  
class action_MF5
{
private:
    double center;
    double width;
    SCALE express;

    double x;
    double y;

public:
    action_MF5(double _center, double _witdth, SCALE _express){
        y = 0.0; // yの値は、必ず0以上1以下になる
       
        center = _center;
        width = _witdth;
        express = _express;
        
        if (express == LESSLESS){
            x = center - 2.0 * width;
        }
        else if (express == LESS){
            x = center - width;
        }
        else if (express == ZERO){
            x = center;
        }
        else if (express == MORE){
            x = center + width;
        }
        else if (express == MOREMORE){
            x = center + 2.0 * width;
        }
        else{
            printf("wrong scale expression\n");
        }
    };
    
    void func_Max(double b){
        y = max(b, y);
    };
    
// X座標を返す
    double func_X(void){
        return x;
    };
    
    // (最大値で更新された、最後の)Y座標を返す
    double func_Y(){
        return y;
    };

};

int main()
{
    // ダイエット経過期間
    condition_MF3 Period_Short(14, 14, LESS); // 0日
    condition_MF3 Period_Middle(14, 14, ZERO); // 14日
    condition_MF3 Period_Long(14, 14, MORE); // 28日

    // いわゆる「停滞期」(14日間あたりの平均減重変化量)
    condition_MF3 WeighChange_Small(1.0, 1.0, LESS); // 0kg
    condition_MF3 WeighChange_Middle(1.0, 1.0, ZERO); // 1kg
    condition_MF3 WeighChange_High(1.0, 1.0, MORE); // 2kg

    // 苦痛度
    condition_MF3 Suffer_Zerol(400.0, 400.0, LESS); // 0
    condition_MF3 Suffer_Middle(400.0, 400.0, ZERO); // 400
    condition_MF3 Suffer_Hight(400.0, 400.0, MORE); // 800

    // BMI
    condition_MF5 BMI_lowlow(22.0, 3.0, LESSLESS); // 痩せすぎ(15.0)
    condition_MF5 BMI_low(22.0, 3.0, LESS);// 痩せぎみ(19.0)
    condition_MF5 BMI_Normal(22.0, 3.0, ZERO);// 普通(22.0)
    condition_MF5 BMI_High(22.0, 3.0, MORE); // 太りぎみ(25.0)
    condition_MF5 BMI_HighHigh(22.0, 3.0, MOREMORE);// 太りすぎ(28.0)

    // 一日の摂取カロリー
    action_MF5 Eat_LittleLittle(2500, 1000, LESSLESS); // 500 Kcal
    action_MF5 Eat_Little(2500, 1000, LESS);// 1500 Kcal
    action_MF5 Eat_Normal(2500, 1000, ZERO);// 2500 Kcal
    action_MF5 Eat_Lot(2500, 1000, MORE);// 3500 Kcal
    action_MF5 Eat_LotLot(2500, 1000, MOREMORE);// 4500 Kcal



    
    
    // 超シンプルシミュレータ投入
    // 体重変動シミュレーションプログラム
    //基礎代謝量と求め方	?ハリス・ベネディクト方程式(日本人版) 計算式
    //http://www.kintore.info/kisotaisya_mass/index.cgi
    //【計算式】
    // 男性 66.5+(体重kg×13.8)+(身長cm×5.0)-(年齢×6.8)
    // 女性 665.1+(体重kg×9.6)+(身長cm×1.9)-(年齢×7.0)							
    // 江端智一 2014日2月4日現在のデータを使って計算
    double weight = 78.0;  // 開始時の体重 78.0kg
    double lengthw = 172.0;  // 身長 172cm
    double age = 49.0 + 94/365;  // 開始時の年齢 49歳と94日 (2014年2月4日現在)

    // 最初の基礎代謝カロリー 男性  66.5+(体重kg×13.8)+(身長cm×5.0)-(年齢×6.8)
    double consumption_calorie =  
        66.5 + weight * 13.8 + 172.0 * 5.0 - age * 6.8;
    // このカロリーに運動消費カロリーを加えて、
    // トータルの一日の消費カロリーを算出する

    // (現在の体重 66.5kgにおいて)一日運動消費カロリー 708kcalと推定し、
    // このカロリーは、体重に比例するものと仮定する。
    consumption_calorie += weight/66.5 * 708.0;
    printf("consumption_calorie = %f\n",  consumption_calorie);

    double last_weight[14]; // 過去14日分の体重
    
    // 最初は全部同じ体重とする 14日経過までは同じ体重とする
    for (int i = 0; i++; i < 14){
        last_weight[i] = weight;
    }

    // ここからループ開始
    for (int day=0; day < 1460; day++){ // 1460日は、ちょうど4年分の日数
        // 7kcal = 1g = 0.001kg とする    

        // 体重データを一日分ずらす
        for (int i = 0; i++; i < 14-1 ){
            last_weight[i+1] = last_weight[i];
        }
        last_weight[0] = weight;
        
        // 線形補完の傾きだけを求める(14日分)
        // http://d.hatena.ne.jp/rainlib/20090112/1231735459
        double k1=0,k2=0,k3=0,k4=0;
        for (int i = 0; i++; i < 14 ){
            k1 += (double)i * (double)i;
            k2 += (double)i * last_weight[i];
            k3 += (double)i;
            k4 += last_weight[i] *last_weight[i];
        }
        double dW = (14.0 * k2 - k3 * k4) / (14.0 * k4 - k3*k3); // 14

        // BMIの計算式 体重(Kg)÷身長(m)÷身長(m) 江端の身長172cm
        double bmi = weight / 1.72 / 1.72;
        
        // [ルール1] ダイエット開始直後は、「無条件にがんばれる」
        double r1 = min(Period_Short.func(day));
        Eat_Little.func_Max(r1);
        //printf("r1: %f\n",r1);
        
        //printf("Eat_Little.func_X() = %f\n",Eat_Little.func_X());
        //printf("Eat_Little.func_Y() = %f\n",Eat_Little.func_Y());
        
        // [ルール2] ダイエット一ヶ月を過ぎても、停滞し続けると「切れる」
        double r2 = min(Period_Long.func(day),WeighChange_Small.func(dW));
        Eat_LotLot.func_Max(r2);
        //printf("r2: %f\n",r2);
        
        // [ルール3] ダイエット2週間を過ぎて、停滞し続けると「緩んでくる」
        double r3 = min(Period_Middle.func(day),WeighChange_Small.func(dW));
        Eat_Normal.func_Max(r3);
        //printf("r3: %f\n",r3);
        
        // [ルール4] 停滞期がなく順調に体重が落ちている場合は「がんばれる」
        double r4 = min(WeighChange_High.func(dW));
        Eat_Little.func_Max(r4);
		//        printf("r4: %f\n",r4);
        
        // [ルール5] ダイエット一ヶ月を過ぎて、再び太り出してくると、またダイエットを再開してしまう
        double r5 = min(Period_Long.func(day),BMI_High.func(bmi));
        Eat_Little.func_Max(r5);
        //printf("r5: %f\n",r5);
        
        // [ルール6] ダイエット一ヶ月を過ぎて、太り過ぎると、滅茶苦茶なダイエットを始めてしまう
        double r6 = min(Period_Long.func(day),BMI_HighHigh.func(bmi));
        Eat_LittleLittle.func_Max(r6);

        //printf("r6: %f\n",r6);
		/*        
        printf("Eat_LittleLittle.func_X() = %f\n",Eat_LittleLittle.func_X());
        printf("Eat_LittleLittle.func_Y() = %f\n",Eat_LittleLittle.func_Y());
        printf("Eat_Little.func_X() = %f\n",Eat_Little.func_X());
        printf("Eat_Little.func_Y() = %f\n",Eat_Little.func_Y());
        printf("Eat_Normal.func_X() = %f\n",Eat_Normal.func_X());
        printf("Eat_Normal.func_Y() = %f\n",Eat_Normal.func_Y());
        printf("Eat_Lot.func_X() = %f\n",Eat_Lot.func_X());
        printf("Eat_Lot.func_Y() = %f\n",Eat_Lot.func_Y());
        printf("Eat_LotLot.func_X() = %f\n",Eat_LotLot.func_X());
        printf("Eat_LotLot.func_Y() = %f\n",Eat_LotLot.func_Y());
        */
        
        double source_calorie =  
            (Eat_LittleLittle.func_X() * Eat_LittleLittle.func_Y() + 
             Eat_Little.func_X() * Eat_Little.func_Y() +
             Eat_Normal.func_X() * Eat_Normal.func_Y() +
             Eat_Lot.func_X() * Eat_Lot.func_Y() +
             Eat_LotLot.func_X() * Eat_LotLot.func_Y() )  
            /
            (Eat_LittleLittle.func_Y() + 
             Eat_Little.func_Y() +
             Eat_Normal.func_Y() +
             Eat_Lot.func_Y() +
             Eat_LotLot.func_Y() ) ;
        
        printf("\n source_calorie = %f\n",source_calorie);

        double diff_weight = (source_calorie - consumption_calorie)/7.0 / 1000.0;
        weight += diff_weight;
        age += 1.0/365.0;
        consumption_calorie =  66.5 + weight * 13.8 + 172.0 * 5.0 - age * 6.8;
        consumption_calorie += weight/66.5 * 708.0;
        //       printf("day:%d\tweight = %f\tconsumption_calorie =%f\n", day,weight, consumption_calorie);
    }



}

ファジィ推論

 

2022/09,江端さんの技術メモ

長女が125CCのバイクに乗り替えてから、放置し続けてきたバイクが動かなくなった、というので、廃棄処分にするか相談を受けていたのですが ―― 私には、どうにも故障に見えない。

 

バイク屋で見て貰った時間は、3秒くらい。

簡単に言えば、「スピードメータに、オイル交換やらバッテリーやらの電飾表示が出ないので、充電してもダメ」ということらしい。ただし「スターターが壊れている可能性もあるが、まずはバッテリーを交換してみないと分からん」と言われました。

で、早速Amazonで購入。もっとも安いもので2000円、リチウムは16000円もするのでスコープ外として、今回はこれにしました。

購入の判断は、評価者数の多さと(1040個の評価)と、

評価の分布でした。私は、こういう正規分布に近い評価を見ると、安心できます。

さて、これが届くまでの間、バイクの空気圧の補充をしに、ガススタンドにいっていました。150~200PKは必要なのに、90くらいしか入っていませんでした。


本日の昼前にバッテリーが届いたので、さきほど5分くらいで、バッテリー交換しました(一度やっているので、コツは掴んでいる)。

ちゃんと充電されて配送されてきた。感心、感心。

バッテリーボックスの回りにガムテープを貼っているのは・・・以前、きちんとバッテリー収納ボックスを開けてみたはいいが、閉めれなかったんだろうな~、と推測。 → 保険証を貼りつけていたことを思い出した。

古いバッテリーを取り出す。

新しいバッテリーに交換。

無事、インジケータの表示とセル起動を確認して、バイク復活を確認しました。

バッテリー不良ごときで、バイクが廃棄されたかもしれないかも、と考えると、さすがの私も「もったいない」と思います。

敢えていうのであれば、「面倒くさい」あたりがしっくりきます。

3000円程度であれば、今後もバッテリー交換を繰替えせば良いと思うけど、もしかしたら、バッテリー液交換(で遊ぶ)かもしれないので、自分の為に、マニュアルを添付しておきます。

しかし、我が家には、当然のように、テスターや、電圧可変ができる安定化電源(ジャンク屋で拾ってきた)があるのだけど、一般家庭にはないかもしれません。

こういうDIYをサクっとできるのは、そういうことが好きな人間だけの特権かもしれません。

以上