2023年9月30日土曜日

C言語:小数→整数への丸めの処理の違い

event_note22:46 editBy ケイ forumNo comments

概要

 C言語で小数→整数への丸めをするとき、floor関数とint型へのキャストで結果が違うことに最近気づきました。

正の値であれば同じなんですが、負の値だと異なる結果となります。

 

検証

実際にプログラムで検証します。
#include<stdio.h>
#include<math.h>
int main() 
{
    double val[] = {.5, 1.5, -.5, -1.5};
    for(int t=0; t<sizeof(val)/sizeof(double); t++)
    {
        printf("val=%5.1f   (int)val=%3d   floor(val)=%3.0f\n", 
            val[t], (int)val[t], floor(val[t]));
    }
}
 
検証環境はVisual Studio 2019のコマンドプロンプトです。
CLコマンドでコンパイルします。

実行結果は以下の様になります。

floor関数は数値が小さい整数に、キャストは絶対値が小さい整数に丸めが行われます。

なお、floor関数の戻りはdoubleのままです。

切り捨てとして期待する処理は一般的にどちらなのでしょうか。

考察

floor関数は切り捨てとして説明されることがありますが、実際は「引数を越えない最大の整数値を返す」処理を行います。

丸めについては調べると色々な考え方があるようで、とりあえず一つの基準としてJISの規格を参考にします。

JIS規格 Z8401「数値の丸め方」ではいわゆる四捨五入で、負数の場合は絶対値に適用すると説明をしています(規則B)。
切り上げ、切り捨ての説明はありませんが同様に考えると、キャストの処理の方がJIS的と言えそうです。

JIS規格は以下から検索できます。(但しユーザー登録が必要)

負数の丸めがどのような処理とするのかは、システムで統一しておかないと不具合になりますね。そういう記事もありました。


2020年12月30日水曜日

C言語でJSON解析をするためにライブラリJanssonを使用する

event_note18:01 editBy ケイ forumNo comments

概要

C言語でJSONの解析を行うライブラリです。
参考サイトはいろいろありますが、今一つわかりにくいため
Linux環境で使うための手順を示します。

 

準備


まず以下のリンクよりソースファイルをダウンロードします。
http://www.digip.org/jansson/releases/jansson-2.13.1.tar.gz
 
このファイルをLinux上の適当なディレクトリに配置します。
以下のコマンドで展開します。

tar zxvf jansson-2.13.1.tar.gz


展開したディレクトリ内にて
以下のコマンドを実行して jansson をビルドします。

./configure --prefix=/usr --disable-static && make

 

root ユーザーになって以下を実行します。

sudo make install

これでライブラリが使用できるようになります

使用するには以下のようにヘッダをリンクし

#include <jansson.h>


ライブラリのリンクはコンパイル時に以下のように指定します。

-ljansson


使用例

それでは以下のJSONファイルを読み込んでみます。

このサンプルでは全部の要素ではなく、読みたい項目のみを抜粋して取得します。

 

ファイル:json.txt

{

    "hostname": "127.0.0.1",

    "sendPort": 80,

    "Description":  "Sequential pattern",

    "DependOnSequentialEvent":  {

        "environmentType":  "PHU",

        "valPercent":   83.700,

        "isScript": true,

        "Location": {

            "state1":   98,

            "state2":   44493,

            "state3":   298

        },

        "pict": "ES-JJ0938",

        "serialNo": 31984,

        "currentEvent": true,

        "alive":    "yes",

        "picturesNumber":   2

    },

    "eventState":   "active",

    "eventType":    "DependOnSequentialEvent",

    "cdID": 1,

    "netPonds": 1,

    "dateTime": "2020-10-24 19:13:49"

}

 

main.c

#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <jansson.h>

 

int parseJson(const char *buffer, size_t buflen)

{

    // JSONオブジェクトを入れる変数

    json_error_t error;

    json_t* root;

    json_t* obj;

    const char *str;

    double dValue;

    int iValue;

 

    // JSON全体バッファを読み込む

    root = json_loadb(buffer, buflen, 0, &error);

    if ( root == NULL )

    {

        printf("[ERR]json load FAILED\n");

        return 1;

    }

 

    printf("------------------------------------\n");

    obj = json_object_get(root, "dateTime");

    if(json_is_string(obj))

    {

        str = json_string_value(obj);

        printf("dateTime: %s\n", str);

    }

 

    obj = json_object_get(root, "eventType");

    if(json_is_string(obj))

    {

        str = json_string_value(obj);

        printf("eventType: %s\n", str);

    }

 

    obj = json_object_get(root, "DependOnSequentialEvent");

    if(json_is_object(obj))

    {

        json_t* obj2;

 

        obj2 = json_object_get(obj, "valPercent");

        if(json_is_real(obj2))

        {

            dValue = json_real_value(obj2);

            printf("valPercent(double): %f\n", dValue);

        }

        else if(json_is_integer(obj2))

        {

            iValue = json_integer_value(obj2);

            printf("valPercent(int): %d\n", iValue);

        }

 

        obj2 = json_object_get(obj, "alive");

        if(json_is_string(obj2))

        {

            str = json_string_value(obj2);

            printf("alive: %s\n", str);

        }

 

        obj2 = json_object_get(obj, "isScript");

        if(json_is_true(obj2))

        {

            printf("isScript: true\n");

        }

        if(json_is_false(obj2))

        {

            printf("isScript: false\n");

        }

    }

    printf("------------------------------------\n");

}

 

int main(){

    char block[65535];

    char *file = "json.txt";

    int fd = open(file, O_RDONLY);

    if (fd < 0) {

        // open 失敗

        fprintf(stderr, "open(%s) errror:%d\n", file, fd);

        return -1;

    }

 

    int size = read(fd, block, sizeof(block));

    if (size < 0) {

        fprintf(stderr, "read() errror:%d\n", fd);

        close(fd);

        return -1;

    }

    close(fd);

 

    parseJson((const char*)block, size);

}

 

makefile

EXEC = jsontest

OBJS = main.o \

 

all : clean $(EXEC)

 

clean :

        -rm -f $(EXEC) *.elf *.gdb *.o *~

 

$(EXEC): $(OBJS)

        gcc  -g -O0 -o $@ $(OBJS) -lm -ljansson

 

%.o: %.c

        gcc -c -g3 -O0 -o $@ $<

 

 

実行結果

$ ./jsontest

------------------------------------

dateTime: 2020-10-24 19:13:49

eventType: DependOnSequentialEvent

valPercent(double): 83.700000

alive: yes

isScript: true

------------------------------------

 

解説

まずJSON全体をオブジェクトに取得します(json_loadb関数)

ここではバッファ指定のjson_loadb関数を使用しています。JSON形式でなければエラーとなります。これで全体のオブジェクトを取得します。

 各要素は名前指定で対象オブジェクトに対してのオブジェクトとして取得します(json_object_get関数)

オブジェクト=json_object_get(対象オブジェクト, 文字列);

  

取得したオブジェクトを判断します(is関数)

例えば数値で取得する場合は

json_is_integer(オブジェクト)

true/falseが得られます。この判断は必須ではありませんが、この判断が間違っていると次の取得でエラーとなります。

 

取得します。

例えば上記の数値の場合であれば

json_integer_value(オブジェクト)

で値が得られます。

 

Bool(true/false)を取得する場合は

json_is_true関数, json_is_false関数で判断するのが良いでしょう。

 

下の階層を取得する場合はjson_object_get関数で取得したオブジェクトが下の階層となります。ソースを見ればわかると思います。

 

また、各階層内で取得する際は、文字列指定なので、上から取得しなければならないわけではありません。ソース上でも敢えて取得順はバラバラにしています。

 

注意点

実数(double)を取得するのはjson_real_value関数を使用しますが、この関数では整数表記は取得できません。

事前に、json_is_integer(整数判断)json_is_real(実数判断)をするのが望ましいと思います。

 

使用例(配列)

次は配列(Array)を取得する例です。
以下のJSONファイルはLocationが配列となっています。

 

ファイル:json.txt

{

    "hostname": "127.0.0.1",

    "sendPort": 80,

    "Description":  "Sequential pattern",

    "DependOnSequentialEvent":  {

        "environmentType":  "PHU",

        "valPercent":   83.700,

        "isScript": true,

        "Location": [

        {

            "state1":   98,

            "state2":   44493,

            "state3":   298

        },

        {

            "state1":   198,

            "state2":   144493,

            "state3":   1298

        },

        {

            "state1":   298,

            "state2":   244493,

            "state3":   2298

        }

        ],

        "pict": "ES-JJ0938",

        "serialNo": 31984,

        "currentEvent": true,

        "alive":    "yes",

        "picturesNumber":   2

    },

    "eventState":   "active",

    "eventType":    "DependOnSequentialEvent",

    "cdID": 1,

    "netPonds": 1,

    "dateTime": "2020-10-24 19:13:49"

}

 

main.c

#include <stdio.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <jansson.h>

 

int parseJson(const char *buffer, size_t buflen)

{

    // JSONオブジェクトを入れる変数

    json_error_t error;

    json_t* root;

    json_t* obj;

    const char *str;

    double dValue;

    int iValue;

 

    // JSON全体バッファを読み込む

    root = json_loadb(buffer, buflen, 0, &error);

    if ( root == NULL )

    {

        printf("[ERR]json load FAILED\n");

        return 1;

    }

 

    printf("------------------------------------\n");

    obj = json_object_get(root, "dateTime");

    if(json_is_string(obj))

    {

        str = json_string_value(obj);

        printf("dateTime: %s\n", str);

    }

 

    obj = json_object_get(root, "eventType");

    if(json_is_string(obj))

    {

        str = json_string_value(obj);

        printf("eventType: %s\n", str);

    }

 

    obj = json_object_get(root, "DependOnSequentialEvent");

    if(json_is_object(obj))

    {

        json_t* obj2;

 

        obj2 = json_object_get(obj, "valPercent");

        if(json_is_real(obj2))

        {

            dValue = json_real_value(obj2);

            printf("valPercent(double): %f\n", dValue);

        }

        else if(json_is_integer(obj2))

        {

            iValue = json_integer_value(obj2);

            printf("valPercent(int): %d\n", iValue);

        }

 

        obj2 = json_object_get(obj, "alive");

        if(json_is_string(obj2))

        {

            str = json_string_value(obj2);

            printf("alive: %s\n", str);

        }

 

        obj2 = json_object_get(obj, "isScript");

        if(json_is_true(obj2))

        {

            printf("isScript: true\n");

        }

        if(json_is_false(obj2))

        {

            printf("isScript: false\n");

        }

 

        obj2 = json_object_get(obj, "Location");

        if(json_is_array(obj2))

        {

            int i;

            int arraysize = json_array_size(obj2);

            printf("Location arraysize: %d\n", arraysize);

 

            for(i=0; i<arraysize; i++){

                json_t* obj3 = json_array_get(obj2, i);

                if(json_is_object(obj3)){

                    json_t* obj4;

                    obj4 = json_object_get(obj3, "state1");

                    if(json_is_integer(obj4)){

                        iValue = json_integer_value(obj4);

                        printf("[%d] state1: %d\n", i, iValue);

                    }

                    obj4 = json_object_get(obj3, "state2");

                    if(json_is_integer(obj4)){

                        iValue = json_integer_value(obj4);

                        printf("[%d] state2: %d\n", i, iValue);

                    }

                    obj4 = json_object_get(obj3, "state3");

                    if(json_is_integer(obj4)){

                        iValue = json_integer_value(obj4);

                        printf("[%d] state3: %d\n", i, iValue);

                    }

                }

            }

        }

    }

    printf("------------------------------------\n");

}

 

int main(){

    char block[65535];

    char *file = "json.txt";

    int fd = open(file, O_RDONLY);

    if (fd < 0) {

        // open 失敗

        fprintf(stderr, "open(%s) errror:%d\n", file, fd);

        return -1;

    }

 

    int size = read(fd, block, sizeof(block));

    if (size < 0) {

        fprintf(stderr, "read() errror:%d\n", fd);

        close(fd);

        return -1;

    }

    close(fd);

 

    parseJson((const char*)block, size);

}

 

makefile

EXEC = jsontest

OBJS = main.o \

 

all : clean $(EXEC)

 

clean :

        -rm -f $(EXEC) *.elf *.gdb *.o *~

 

$(EXEC): $(OBJS)

        gcc  -g -O0 -o $@ $(OBJS) -lm -ljansson

 

%.o: %.c

        gcc -c -g3 -O0 -o $@ $<

 


実行結果

$ ./jsontest

------------------------------------

dateTime: 2020-10-24 19:13:49

eventType: DependOnSequentialEvent

valPercent(double): 83.700000

alive: yes

isScript: true

Location arraysize: 3

[0] state1: 98

[0] state2: 44493

[0] state3: 298

[1] state1: 198

[1] state2: 144493

[1] state3: 1298

[2] state1: 298

[2] state2: 244493

[2] state3: 2298

------------------------------------

  

解説

ソースでLocationを取得している箇所が該当しますが、以下のように処理しています。
まず、取得したオブジェクトがArrayであるかを判断します。(json_is_array関数
次に要素数を取得します(json_array_size関数
要素数nがわかればインデックス(0n-1)がわかるので要素数分forでループします。
json_array_get(対象オブジェクト, インデックス)
で各要素が取得できます。あとの処理は同様です。

2017年4月29日土曜日

iPhone5S(元au、今MINEO運用)のiOS10.3.1バージョンアップ

event_note22:59 editBy ケイ forumNo comments

今使っているスマートフォンはiPhone5Sだが、SIMフリー機種ではなく、元々auで契約した機種である。それをコスト削減のため、auを解約してMINEOのSIMで利用するようになった。
プランは音声付プランである。
契約当時は対応iOSのバージョンは7となっており、それをバージョンアップすると使えないというアナウンスがあったためiOSのバージョンアップはずっと見送っていた。
が、さすがにiOS7では非対応のアプリが増えてきて運用に支障が出てきたのでどうしたものかと思っていたが、調べると今は最新のiOSでも使えるようになったとのこと。
理由は良くわからないが、MINEOの説明だと特に何もしていないためau側で何らかの対応がされたのではないかとのこと。

とにかく、最新のiOS10.3.1を入れることにした。
まずはバックアップである。iCloudでバックアップしたが、全部とれているのか今一つ良くわからなかったので、iTunesでもバックアップを行った。

バックアップ完了後はバージョンアップだが、直接スマホからWifi経由でダウンロードして行う手段で実施した。
プロファイルはMINEO運用開始時にインストールしたもの(A1)から変更するわけでもなく、そのまま使用した。

バージョンアップは特に不具合なく終了した。
起動すると新たな機能などのチュートリアルがあったため設定に時間を取られたがiPhoneを探す機能などは万が一のことを考えて有効化した。

通話、通信などは問題ないが、テザリングが出来ないのは今までのアナウンス通り。
ただ、ネットを検索するとできているという報告もある。
で試したいのだが、テザリングを試す以前にテザリングを有効にできない。
設定は

「インターネット共有を設定」をクリックする

説明を追加
「Webに移動」をクリックする




ここでau IDの入力を求められる。
auを解約した後は、以前のID+アンダーバー+解約した日付
となる。
昔のメールを検索すると、「解約したので変更しました」という旨のメールが来ていたのでそのIDでログインする。


結局テザリングを有効にすることはできなかった。
MY AUアプリを使用していると上記のような画面で手詰まりになる。
色々試行錯誤したが、MY AUアプリ上ではログイン自体は出来ているのに対し、設定変更に関する操作はもはや管理対象がないからか すぐエラーとなるのである。

2017年3月5日日曜日

MOUSE Computer WN1001の回復ドライブの作成

event_note11:17 editBy ケイ forumNo comments

MOUSE Computer WN1001の回復ドライブの作成を行った。



<作成>
少々苦労したので試行錯誤した経緯を以下に記録
・コントロールパネル→「回復」→「回復ドライブの作成」にて「回復ドライブの作成ダイアログ」を開く
・「次へ」をクリック
・USBフラッシュドライブを選択し、「次へ」をクリック
・「回復ドライブの作成」で「作成」をクリックをしたところ
「回復ドライブを作成できません」
「回復ドライブの作成中に問題が発生しました」
と表示されて終了。

この問題に対して
・不要と思われるプロセスを停止
・Windows Update
などを行ったが駄目だった。

書き込みに失敗する原因はUSBフラッシュメモリのフォーマットがFAT32だったから。
NTFSでフォーマットしなおして再試行したら作成は完了できた。

書き込まれたUSBフラッシュメモリの中身を確認すると、使用された容量は4GB。
セットアップしてからあまりいじっていないためこんなものなのだろう。

<USBフラッシュメモリからの起動テスト>
作成したものから起動できるかのテストを行った。

普通にUSBをつないだ状態で電源を投入してもUSBからの起動はしなかった。BIOS(UEFI)でのBOOTオプションを設定する必要があるようだ。

電源投入時にF2キーを押していてもBIOS画面には切り替わらない。以下の手順にてBIOS設定画面を表示させる必要がある。

Windows 上から 「 BIOS 設定 」 画面を表示する方法 ( Windows10 )
https://www2.mouse-jp.co.jp/ssl/user_support2/sc_faq_documents.asp?FaqID=21649

手順としては
・SHIFTキーを押しながら再起動
・「オプションの選択」画面が表示されるので、「トラブルシューティング」を選択
・さらに「詳細オプション」を選択
・さらに「UEFIファームウェアの設定」を選択する
・確認画面にて「再起動」を選択する

そうすると、再起動し、設定画面が現れる。
ここからBOOTオプションでUSBメモリが選択できるようにする。

Save&Exitで設定画面を抜けると、USBから起動する。

「キーボードレイアウトの選択」から「Mircrosoft IME」を選択


「オプションの選択」より「トラブルシューティング」を選択。

「トラブルシューティング」 から「ドライブから回復する」を選択

「ドライブから回復する」画面が表示される。
これ以降は試していない


book-station