non vorrei lavorare

昔はおもにプログラミングやガジェット系、今は?

node.jsでtruncatable primeを試したら、OpenSSLをビルドした件

おはようございます。先週は次男が発熱の為、自分と次男だけ実家で生活していました。幸い次男はインフルエンザは陰性でしたが、なかなか熱が平熱に戻らず、結局、1週間ほど実家で過ごしていました。@kjunichiです。

背景

Mathematicaの公式の以下のツイートで知った。

truncatable primeをnode.jsで計算してみた

node.jsのv10からbigintがサポートされる

以下のQiitaの記事にあるように、node.jsでもbigintがv10以降サポートされ、大きな数も手軽に扱えるように なっている。

qiita.com

愚直な素数判定だと日が暮れても終わらなかった

Wikipediaには計算機で簡単に計算できる]と書いてあるが、真に受けて愚直な実装で試したら、日が暮れても終わらなかった。(三日三晩放置したが、半分も求めることが出来なかった。。。)

ja.wikipedia.org

手っ取り早くネイティブモジュールで時短を図った

そこで、以前の記事を思い出し

https://abrakatabura.hatenablog.com/entry/2014/11/28/175853

このbignumモジュールの素数判定を利用して高速化を図ろうとした。

WindowsではOpenSSLのビルドが必要に!

bignumモジュールのビルドでWindowsではOpenSSLの.libファイルが必要になった。DLLファイルはnode.jsに含まれているが、 Windowsは.libファイルがnpmモジュールのビルドに必要なため、これを用意する必要があった。

OpenSSLのビルドにはPerlが必要となったり、なかなか家族旅行中のSurface Goでの作業では 大変だった。

そう言えば、以前、東京Node学園で大津さんの「祝Node-v10リリース これまでのNodeの振り返り」でもPerlが使われているという話を思い出した。そう、OpenSSLのビルドにはPerlが必要なのだった。

また、とにかく最新のOpenSSLのバージョンで良いわけでもなく、Node.jsで利用している系のバージョンに限定されている模様。 今回は OpenSSL_1_0_2-stable を使用した。 ビルドは

  • INSTALL.W64
  • INSTALL.W32

を参考にすすめ、インストール先をbignumモジュールの参照している openssl-win64 を指定する。

成果物

WindowsはにOpenSSLをビルドした後、macOSLinuxは事前準備なしで

npm i bignum

試行錯誤したままのコードなので、ちょっと恥ずかしいけど。

const bignum = require('bignum')

const cachePrime = {}
let findDigit = 0
let counter = 1
let cacheCounter = 0
let numOfTruncatablePrime = 1

const isPrime = (n) => {
    const bn = bignum(n.toString())
    const r = bn.probPrime(80)
    //console.log(`r = ${r}`)
    return r
}

const getNum = () => {
    if (findDigit > 0) {
        //console.log(cachePrime[findDigit - 1][cacheCounter])
        if (cachePrime[findDigit - 1][cacheCounter] === undefined) {
            return -1
        }
        const sNum = counter.toString() + cachePrime[findDigit - 1][cacheCounter++].toString()
        //console.log(sNum)
        num = BigInt(sNum)
        if (cacheCounter >= cachePrime[findDigit - 1].length) {
            cacheCounter = 0
            counter++
        }
    } else {
        num = BigInt(counter)
        counter++
    }
    if (counter > 9) {
        findDigit++
        //console.log(`findDigit = ${findDigit}, counter = ${counter}`)
        cachePrime[findDigit] = []
        counter = 1
        cacheCounter = 0
    }
    //console.log(`${num}`)
    return num
}

const check = (num) => {
    if (!isPrime(num)) {
        return
    }
    let cnum = num.toString()
    const digit = cnum.length

    console.log(`truncatable prime (${numOfTruncatablePrime++}[${digit}]) : ${num}`)
    cachePrime[digit - 1].push(num)
}

cachePrime[0] = []
while (true) {
    const num = getNum()
    if (num > 0) {
        //console.log(`num = ${num}`)
        check(num)
    } else {
        break
    }
}

参考資料

関連記事

14年前の記事

12年前の記事

7年前の記事

5年前の記事

2019年、あけましておめでとうございます

こんばんは、子供達は相変わらずマイクラにハマって喧嘩しながらも、なんだかんだ兄弟で遊んでいます。@kjunichiです。

f:id:kjw_junichi:20190104110224j:plain

2019年もお世話になりそうなサービスやサイト

GitHub

日中アクセスを遮断されているものの、 CV代わりになり、海外からの誘いが来るような活動ができるように頑張る。

今年こそ、なにか知育関連のリポジトリ作れると良いなぁ。

ISSUEリーダーとしても引き続き利用w。

Cloud9 IDEAWS

GitHubの遮断の為に、昨年の夏以降は、AWS版を使うようになった。

SSHクライアントととしての利用が大変便利。

はてな

はてなブログ

週に1記事程度の頻度で書いていきたい。

はてブ

日中の気になったページのあとで読むに利用。最近はホッテントリのページも結構見るようになった。自分の記事がマイインタレストに入ることもたまにある。

Runstant

仕事ではlight版にお世話になることがある。

Heroku

  • Twitterの自作のクライアントを動かしている。
  • JuliaもDockerベースで動かしている.

Google App Engine

自作の外貨預金管理システムを動かしている。 Java8に移行しろと昨年警告メールが来ている。

Herokuと違い、リポジトリクラウド側にないのが自分の開発スタイルと合わず、今後も 新規Webアプリの開発の可能性は低い。でもHerokuより優れている点としてCron的なことが 出来るので、定期実行するサービスの新規追加はあり得る。

OneNote

Evernoteからこちらに移って利用中。 もう少し、活用したいとは思うものの、秘密にする知識や情報もなく、GithubのGistで事足りることも 多い気がする。

Twitter

検索用途にも利用中。

DropBox

実家で取ってくれた息子の写真や、こちらで撮影した息子の写真の 送付に今年も活躍する予定。

Facebook

親戚やごく親しい友人とのプライベートな写真や動画のシェアに今年も活躍しそうです。

Qiita

今年も自分の知識の整理に活用できると良いかな

feedly

なんだかんだでGoogleリーダーから移行して以来、使っている。

Foursquare

お出かけの記録に利用。

IFTTT

GMail

iCloudのメールも使って入るが、メインはこちら。

YouTube

YouTuberへのわずかな望みを繋げるべく、今年も作品をアップロードするぞ。

Google Drive

自作サービスのストレージとしての利用や、リアルタイムコラボレートAPIに興味あり

dev.to

英語でブログを今年も続けられるといいなぁ

Hacker New

日中Github遮断されてるので結構読んだ。

teratail

たまに、参考になる質問や、初心者の扱い方の勉強にもなる気がする

japanese.stackexchange.com

日本語と英語が同時に勉強できるお得なサイトw

amazon

プライム会員でいろいろタダで映画見れるが昨年は結構課金して映画を子供たちと見てしまった。 今年はもう少し節約したところw。

Jsdo.it

過去の作品のコードを復習するのにはまだまだ利用しそう。

Evernote

無料枠のデバイスの台数の制約がきついので、IFTTTで連携してはてブを保存してはいるが、 あまり活用していない、代りのOneNoteを利用がそこそこ定着。

Instagram

プログラミング関連の画像や、スクリーンショットを載せると海外の方からいいねをいただくので 病みつきにw。

関連記事

15年前の記事

12年前の記事

7年前の記事

5年前の記事

Arduinoで測った室温をデスクトップマスコットのgopheronに表示させた

背景

arduinoを手に入れて、何かPCと連携してみたくなった。

Arduinoで測った室温をデスクトップマスコットのgopheronに表示

構成

  • node.jsでarduinoの計測結果をシリアルポート経由で受信し、ファイルに出力
  • ファイル出力はリダイレクトで実現

node.jsでarduinoの計測結果をシリアルポート経由で受信

シリアル通信には、以下のモジュールを使用した。

serialport.io

インストールは以下のようにできる。

npm i -S serialport

このserialportモジュールはパーサーをいくつか選べるようで、今回はreadLineパーサーを使って、 arduino側で"\n"を入れることで、このパーサーと連携した。

node.jsの受信部

const SerialPort = require("serialport")
const Readline = SerialPort.parsers.Readline
const sp = new SerialPort("/dev/cu.usbmodem14201", {
    baudRate: 9600
})
const parser = new Readline()
sp.pipe(parser)

parser.on('data', (line) => {
    console.log(`line : ${line}`)
})

sp.on("open", () => {
    console.log('open')
})

arduino側のコード

arduino側はサンプルのコードの結果をシリアルポートに書き込むように処理を追加した程度。

//www.elegoo.com
//2016.12.9

#include <LiquidCrystal.h>
int tempPin = 0;
//                BS  E  D4 D5  D6 D7
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
void setup()
{
  lcd.begin(16, 2);
  Serial.begin(9600);
}
void loop()
{
  int tempReading = analogRead(tempPin);
  // This is OK
  double tempK = log(10000.0 * ((1024.0 / tempReading - 1)));
  tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK * tempK )) * tempK );       //  Temp Kelvin
  float tempC = tempK - 273.15;            // Convert Kelvin to Celcius
  float tempF = (tempC * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit
  /*  replaced
    float tempVolts = tempReading * 5.0 / 1024.0;
    float tempC = (tempVolts - 0.5) * 10.0;
    float tempF = tempC * 9.0 / 5.0 + 32.0;
  */
  // Display Temperature in C
  lcd.setCursor(0, 0);
  lcd.print("Temp         C  ");
  // Display Temperature in F
  //lcd.print("Temp         F  ");
  lcd.setCursor(6, 0);
  // Display Temperature in C
  lcd.print(tempC);
  Serial.print(tempC);
  Serial.print("\n");
  // Display Temperature in F
  //lcd.print(tempF);
  delay(500);
}

デスクトップマスコットへの通信コマンド

デスクトップマスコットはWebSocketを受け付けているので、 先ほどの計測した室温のファイルをtailコマンド風に追加された行を読み込んで、これを WebSocketに書き込む。

アイコンは例によって、PNGを同期APIのfs#readFileSyncで読み込んで、base64でHTMLに埋めむ実装

node.jsでtailコマンド風の処理をする

以下のモジュールでnode.jsでtailコマンド風にファイルに追加された行を取得できる。

npm i -S node-tail

tail風の処理は以下のようになる。

const Tail = require('tail').Tail

const filename = "/path/to/roomTemp.dat"

const tail = new Tail(filename);

tail.on('line', (line) => {
        const temp = line.split(':')[1]
        console.log(`temp : ${temp}`)
}

tail.on('close', () => {
      console.log('watching stopped');
})
     
tail.watch()

setTimeout(()=>{
     tail.unwatch()
},5000)
const socket = require('socket.io-client')('http://localhost:5050')
const Tail = require('tail').Tail
const fs = require('fs')

const filename = "/Users/kjunichi/work/nodejs/arduino/serial/roomTemp.dat"
const logo = fs.readFileSync("./ArduinoCommunityLogo.png")

socket.on('connect', () => {
    const tail = new Tail(filename);
    let count;

    socket.on('gopher recv', (msg) => {
        console.log(`recv: ${msg}`)
        count--
        if (count <= 0) {
          process.exit(0)
        }
    })

    const displayTemp = (temp) => {
        count=2;
        socket.emit('gopher front', '1000')
        const html = `<img width="192" src="data:image/png;base64,${logo.toString('base64')}"><span style=\"font-size:larger;font-family: 'Segoe UI Emoji';\"><div style=\"font-size: 48px;wrap\">🌡 ${temp}℃</div></span>`
        socket.emit('gopher sendHtml', html)
        tail.unwatch()
    }

    tail.on('line', (line) => {
        const temp = line.split(':')[1]
        console.log(`temp : ${temp}`)
        displayTemp(temp)
    })
     
    tail.on('close', () => {
      console.log('watching stopped');
    })
     
    tail.watch()
})

実行結果

youtu.be

今回使用したArduino

関連記事

gopheronつながり

4年前の記事

3年前の記事

2年前の記事