プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

脱毛の痛みを数値化してみた

私「髭っていらねぇし、剃るの面倒くさいし、いい加減脱毛しようかと思ってんだけど、通うの面倒くさいんだよねぇ」

母「ていうか、あんた全身脱毛したら?」

私「は?」

母「体毛あると介護するのに迷惑なのよ。あんた身寄りのない痴呆老人になるんだから、せめてよそ様の迷惑を減らしておきなさい。」

私「え?マジ?」

 というわけで、私事ですが、現在介護脱毛中です。

 デブで性悪の上に不潔とか、ウンコ製造機どころか、私がウンコそのものだった様です。人間は諦めても、せめてウンコ製造機ぐらいにはなりたい。

 え?痩せろ?………いいですか、そもそも痩せれるなら太らないのです。

 

 さて、この脱毛ですが、痛いです。漏らすぐらいには痛いです。

 いや、正直、平時の肩や首の方が痛いので、大した痛みだとは思わなかったのですが、それでもちょっとした覚悟は必要ですね。ちなみに、今のところ人生で一番痛かったのは、長さで言えば歯の矯正、瞬発力で言えば鼻中隔湾曲症の止血してる詰め物(鼻の穴に親指ぐらいの太さのものが入ってたぞ)を抜いた瞬間ですかね。

 さて、大したことないとはいえ、痛いことは痛いわけです。この痛み、実際後どのぐらい続くのでしょうか? 説明では完全脱毛まで2年はかかるという話でしたが、本当なの? 数値として示してほしい。

 というわけで、ちょっとシミュレーションしてみた。

 

前提条件

 

  • 毛は個々に固定の毛周期を持つと仮定
  • 毛は休止期と成長期の2つと仮定(退行期は考慮しない)
    • 毛がどちらの期間にあるかは一本一本ランダムに異なるとする
  • 脱毛をすると、成長期の毛を確率で殺せると仮定
    • 休止期の毛は殺せないと仮定
  • 脱毛をすると、成長期の毛は必ず痛むと仮定
  • 脱毛をすると、休止期の毛は75%が痛むと仮定
  • 知覚する痛みは、痛みを発生させた毛の本数に比例すると仮定

 

コード

KillHair.cpp

#include <iostream>
#include <cstdint>
#include <random>
#include <cmath>

constexpr size_t size = 1000000; // シミュレートする毛の本数
constexpr uint32_t span = uint32_t(365 * 1.5); // 毛周期の日数
constexpr double rate = 0.7; // 休止期毛の割合
constexpr double killRate = 1; // 成長期の毛を殺害できる確率
constexpr uint32_t killSpan = 60; // 脱毛する周期
constexpr double tdamageRate = 0.75; // 休止期毛が痛む確率

template<class I>
I saturation(I min, I max, I value)
{
  return std::min(std::max(min, value), max);
}

struct Hair {
  uint32_t lifeSpan;
  double rateOfTelogen;// 休止期の割合. 退行期は無いものとする
  uint32_t date; // lifeSpan * rateOfTelogen より小さければ休止
  bool telogen; // 休止か否か
  bool dead; // タヒんだ毛

  static bool isTelogen(uint32_t date, uint32_t lifeSpan, double rateOfTelogen)
  {
    return date < rateOfTelogen * lifeSpan;
  }

  /**
   * 初期化。若干乱数によって指定値からぶれるようにしている。
   * @param span 毛周期
   * @param rate 休止期の割合
   * @param rand 0~1の一様分布な乱数
   */
  template<class Random> void init(uint32_t span, double rate, Random& rand) {
    lifeSpan = uint32_t(span * (1 + (rand() - 0.5) * 0.1));
    rateOfTelogen = saturation(0.1, 1.0, rate * (1 + (rand() - 0.5) * 0.1));
    date = ((uint32_t)(rand() * lifeSpan)) % lifeSpan;;
    telogen = isTelogen(date, lifeSpan, rateOfTelogen);
    dead = false;
  }

  /**
   * 脱毛実行
   * @param rate 殺毛率
   * @param rand 0~1の一様分布な乱数
   * @return 毛がタヒんだかどうか。もともとタヒんでいた場合はfalse
   */
  template<class Random> bool kill(double rate, Random& rand) {
    if (dead || telogen) return false;

    if (rand() < rate) {
      dead = true;
      return true;
    }
    return false;
  }

  /**
   * 殺毛の痛み
   */
  uint32_t killDamage() {
    if (dead) return 0;
    if (!telogen) return 1;
    // 休止期のすべてが痛いのは直観に反する
    // 休止期のx%が痛むと仮定
    if (date < rateOfTelogen * lifeSpan * tdamageRate) return 1;
    return 0;
  }

  bool alive() const { return !dead; }

  /**
   * 日にちを更新する。
   */
  void nextDay() {
    if (dead) return;
    date = (date+1) % lifeSpan;
    telogen = isTelogen(date, lifeSpan, rateOfTelogen);
  }
};


int main(int argc, char const *argv[])
{
  std::vector<Hair> hairs;
  hairs.resize(size);

  std::random_device seed_gen;
  std::mt19937 engine(seed_gen());
  std::uniform_real_distribution<> dist(0, 1.0);
  auto r = [&]() { return dist(engine); };
  for(auto& h: hairs) {
    h.init(span, rate, r);
  }

  size_t alive = size;
  uint32_t kill = 0;
  uint32_t killCount = 0;
  uint32_t firstDamage = 0;
  while(alive) {
    if (!kill) {
      kill = killSpan;
      uint32_t damage = 0;
      uint32_t kills = 0;
      for(auto& h: hairs) {
        damage += h.killDamage();
        if (h.kill(killRate, r)) {
          alive--;
          kills++;
        } else {
          h.nextDay();
        }
      }
      if (killCount == 0) firstDamage = damage;
      double damageRate = std::ceil(((double)damage / firstDamage) * 100);
      double alives = ((double)alive / (double)size) * 100;
      killCount++;
      std::cout << "[" << killCount << "回目] 痛み: " << damageRate << ", 除毛数: " << kills << ", 残存率: " << alives << "[%]" << std::endl;
      if (kills == 0) break;
    } else {
      for(auto& h: hairs) {
        h.nextDay();
      }
    }
    kill--;
  }
  std::cout << (killCount * killSpan) << " 日, " << ((killCount * killSpan)/365.0) << " 年" << std::endl;
  return 0;
}

以下のパラメータを直接弄って遊ぶ。

constexpr size_t size = 1000000; // シミュレートする毛の本数
constexpr uint32_t span = uint32_t(365 * 1.5); // 毛周期の日数
constexpr double rate = 0.7; // 休止期毛の割合
constexpr double killRate = 0.8; // 成長期の毛を殺害できる確率
constexpr uint32_t killSpan = 60; // 脱毛する周期
constexpr double tdamageRate = 0.75; // 休止期毛が痛む確率

実行は以下。

g++ -O3 KillHair.cpp && ./a.out

 

結果

 まずは、成長期の毛を必ず殺せる(killRate = 1)とした場合の結果を見てみましょう。

 他のパラメータは毛周期 1.5年(大体半年~1年半ぐらいらしい)、休止期の割合は70%で、そこまで変な値ではないと思う。(頭髪以外の休止期の割合は6~8割ほどらしい) 陰毛などは毛周期が3年ぐらいらしい。

[1回目] 痛み: 100, 除毛数: 299395, 残存率: 70.0605[%]
[2回目] 痛み: 64, 除毛数: 110091, 残存率: 59.0514[%]
[3回目] 痛み: 51, 除毛数: 110260, 残存率: 48.0254[%]
[4回目] 痛み: 38, 除毛数: 109903, 残存率: 37.0351[%]
[5回目] 痛み: 24, 除毛数: 109849, 残存率: 26.0502[%]
[6回目] 痛み: 14, 除毛数: 109776, 残存率: 15.0726[%]
[7回目] 痛み: 14, 除毛数: 108899, 残存率: 4.1827[%]
[8回目] 痛み: 6, 除毛数: 41825, 残存率: 0.0002[%]
[9回目] 痛み: 1, 除毛数: 2, 残存率: 0[%]
540 日, 1.47945 年

 100% 毛を殺せる技術があったとしても、9回は殺毛しないと除去しきれないらしいですね。この場合、1.5年はどうあがいても脱毛にかかるようです。ちなみに、除毛周期を90にしたら、6回で1年半でした。

 毛周期が長い3年ぐらいだと大体15回(2.5年)ぐらいはかかるみたいです。毛周期が1年だと6回ぐらい、毛周期が半年だと除毛周期60日だと収束しなくて30日とかにしないとだめでした。(その場合でも1年)

 痛みは、一回目に感じると想定される痛みを100とした相対ダメージで表示しています。この結果だと、2回目のダメージは1回目のダメージの64%という意味です。

 次に、毛を殺せる確立を80% (killRate = 0.8)ぐらいにしてみましょう。完全脱毛の定義って脱毛後に生えてくる毛が10%~20%以下のことを言うらしいし、こんなもんかな?

[1回目] 痛み: 100, 除毛数: 240083, 残存率: 75.9917[%]
[2回目] 痛み: 71, 除毛数: 118020, 残存率: 64.1897[%]
[3回目] 痛み: 57, 除毛数: 107706, 残存率: 53.4191[%]
[4回目] 痛み: 44, 除毛数: 107949, 残存率: 42.6242[%]
[5回目] 痛み: 31, 除毛数: 107749, 残存率: 31.8493[%]
[6回目] 痛み: 20, 除毛数: 107761, 残存率: 21.0732[%]
[7回目] 痛み: 18, 除毛数: 107553, 残存率: 10.3179[%]
[8回目] 痛み: 11, 除毛数: 64908, 残存率: 3.8271[%]
[9回目] 痛み: 5, 除毛数: 20363, 残存率: 1.7908[%]
[10回目] 痛み: 2, 除毛数: 4704, 残存率: 1.3204[%]
~省略~
[31回目] 痛み: 1, 除毛数: 0, 残存率: 0.0006[%]
1860 日, 5.09589 年

 

 おっふ、完全除毛するまで5年もかかってしまった。といっても、この完全除毛はシミュレーション本数や乱数に依存するので、これ自体はあまり意味はありません。この結果も0%になったのではなく、除毛できなかったからループが終わってるだけですし。

 完全脱毛の定義の10%以下でみると、やっぱり8、9回ぐらいのようですね。毛周期を3年にしても、13回ほどで10%を下回ります。

 シミュレーション上でも、やはり2年という期間に嘘はなさそうです……

 さて、痛みの項目ですが、見るべきは3回目からの痛みですかね。カウンセラーの方から 「3、4回目からはそんなに痛くないという人が多い」 と言われたのですが、確かに痛みが半減しています。 除毛数自体は2~7回目に大きな差はないので、休止期毛が減ることで痛みが減っているようです。グラフ(↓)でみるとわかりやすいですね。休止期毛が痛む確率を0にすると、2回目以降はしばらく一定になります。

 いずれにせよ、2回目までは、あなた……『覚悟して来てる人』………である必要があるということもわかりますね。

   

まとめ

 かなり大雑把な仮定ですが、確かにシミュレーションからも2年ぐらいかかる、回を重ねるほど痛くなくなり、3、4回目からはさほど痛くないということが数値化できました。

 人の話や体験とかを聞くより、やっぱりこうして数字を見るほうが実感わきますね。

 私はまだ1回目なので、あともう一回は覚悟してきている人となろうと思います。

 なお、個人的には太ももが一番痛かったよ。