Java 桁の大きいLongがマイナスの数字になってしまう

しょぼい失敗ではありますが。(´・ω・`)

例えば、31日間のミリセカンドを取得すべく下記のように定義したとします。

public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000;

この数字は、2,678,400,000です。
26億7840万ミリ秒ですね。

ですが、これを実行すると、実際には、THIRTY_ONE_DAYS_MILL_SEC

-1616567296 

という数字が入っています。マイナスの数字になってしまってるんですよー。

なんで?というと、次のようなことが起きているらしい。

①右辺で計算する時はintで計算されている

②intの最大値が int32ビット-2,147,483,648 〜 2,147,483,64

③桁あふれでマイナス値になってしまっている

なので、右辺で計算するときにlongであると宣言してあげないと、 2,678,400,000 にならないらしいのです…。

末尾にLをつけるだけ。

正しくは、下記の通り。


public static final long THIRTY_ONE_DAYS_MILL_SEC = 31 * 24 * 60 * 60 * 1000L;


osmdroid E/OsmDroid: Please configure a relevant user agent; current value is: osmdroid

AndroidでOpen Street Mapを表示させるライブラリ、OsmDroid。

無料で地図を利用できる幸せ…。開発者の皆様には本当にありがとうございます。


osmdroid E/OsmDroid: Please configure a relevant user agent; current value is: osmdroid

というエラーが表示されて、地図が表示されなくなってしまいました。

下記に情報ありますが、

https://github.com/osmdroid/osmdroid/wiki/Important-notes-on-using-osmdroid-in-your-app

地図の画像をOSMのサーバーからダウンロードする際に、HttpのユーザーエージェントにアプリのIDを入れなくてはいけなくなったようです。

方法は簡単でして地図を表示させるActivityのOnCreateに

Configuration.getInstance().setUserAgentValue(BuildConfig.APPLICATION_ID)

と入れるだけです。(Osmdroid5.6以降)

Android Gradleファイルの階層関係とsettings.gradleについて

Androidの開発をしていると、コードを書いているよりビルドに四苦八苦する時間が多い…ぐらいな気もしてしまいます。

Androidが利用しているビルドツールであるGradleのことについては、大体はAndroid Studioさんがやってくれるので、プログラマの日常業務としてはライブラリの読み込みを編集したり、SDKのバージョンを変更したり、Flavorごとの設定を変更したり…ぐらいなことをやっていて、あんまり理解が進んでいなかったなという気がします。

これにはきっかけがあって、Open Street MapのAndroid組み込み用のサンプルプログラムを自分で使ってみて参考にしようと思ったんですが、Gradle Furyというプラグインを使っていて、結局ビルドできなかったんですよね。Gradle Furyは「Gradleに怒っている人が使う」wwwらしく、POMでいろんなことを定義しちゃおうぜーという試みだったらしいです。

ただ、Gradleのことを全部わかろうというのもちょっと時間の無駄な気がしますね。なので、今回は階層関係と、settings.gradleについて書いておきます。詳しくは、下記の公式サイトで見てみてください。

ビルドの設定

https://developer.android.com/studio/build?hl=JA

Android Studioでプロジェクトを作ると、図のように階層やフォルダができていると思います。(私はWindows 10で開発しています。)


Android StudioでSampleAppというアプリを作ったところ

こんな風に表示されてないよー、という場合は、赤丸してあるところがAndroidになっていると思います。クリックして、「Project Files」にすると、ファイルシステムと同じビューで見れます。この方が、今回はわかりやすいので、この「Project Files」ビューで進めます。

さて、今回最初に話題にしたいのは、下記の水色でマルしたsettings.gradleとbuild.gradleです。

settings.gradleから。中身は下記の一文だけ。


include ':app'

appをつかってビルドしましょうね~って意味でして、これがないと何も始まらないw
今回、一個だけのアプリケーションを使ってビルドするので、一文だけですが、ほかのアプリケーションをモジュールとして利用したい場合、ここにincludeするものが増えていきます。

build.gradleは次の通り。

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
repositories {
google()
jcenter()

}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()

}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

ここでは、全部のアプリケーションに共通のビルドの設定を書いておきます。さっきも書きましたが、今回は一つのアプリケーションだけなので、あまり意味がありませんが、2つ、3つと増えてくると、一つ一つのアプリケーションのGradleファイルにbuildscriptとか書くのは「ええい、面倒!」と思ってくると思いますので、意味があります。

次に、図の紫で囲った、一個下のappフォルダ内のファイルbuild.gradleの説明です。中身は

apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "smart.location.admin.sampleapp"
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}

で、こっちは見慣れた感じだと思います。こっちで利用するライブラリやビルドタイプなどを決めていきます。

今回は本当に触りだけですが、以上です。

NumPy where どの列を調べるか指定する

前回に引き続き、NumPyのちょっと便利な使い方です。

Numpy.where

は配列の中の要素を調べるための有名な関数で、皆さん使ってるかと思います。

標準的な使い方は下記の通りです。

import numpy as np

pieces = np.array([
[1, 0, 0],
[0, 0, 1],
[0, 0, 0]
])

array = np.array([1,0,0])

ndarray = np.where(array == 1, True, False)

print(ndarray)

#下記が出力されます。
[ True False False]

下記のサイトさんなどにも詳しいです。

NumPyで条件に応じた処理を行うwhereの使い方

他のサイトさんであまり紹介されていなくって、今回書いておきたいwhereの使い方が、2次元配列をwhereで調べる時に、列を指定する、というやり方です。

import numpy as np

pieces = np.array([
[1, 0, 0],
[0, 0, 1],
[0, 0, 0]
])

ndarray = np.where(pieces == 1, True, False)[1]

print(ndarray)

#下記が出力されます。
[False False True]

上記のように、whereの後にインデックス[1]をつけると、piecesの2列目(0からカウントなので、1は2番目)が1かどうかを判定して、True, Falseを返してくれてます。

Numpy 2つの配列を比較して重複していない要素を配列にする

前回に引き続き、NumPyについてのちょっと便利な関数を紹介してます。

setdiff1d()

という関数があります。

まずはサンプルです。

import numpy as np

array1 = np.arange(4)
print(array1)

array2 = np.arange(3)
print(array2)

print(np.setdiff1d(array1, array2))

#次のように出力されます
[0 1 2 3]
[0 1 2]
[3]
[0 1 2 3]


[0 1 2]

の差を教えてくれてますね。

ちなみに逆にすると、空の配列が出力されます。

import numpy as np

array1 = np.arange(4)
print(array1)

array2 = np.arange(3)
print(array2)

print(np.setdiff1d(array2, array1))

#次が出力されます。

[0 1 2 3]
[0 1 2]
[]

ちなみに、setdiff1dがあるなら、 setdiff2dがありそうですが、ありません!!

下記のようなやり方でできるようです。(確認はしていません)
https://stackoverflow.com/questions/8317022/get-intersecting-rows-across-two-2d-numpy-arrays