質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

1308閲覧

json_encodeでJavaScriptのオブジェクトに変換をうまくできない

SugiuraY

総合スコア318

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2021/10/08 03:55

編集2021/10/08 04:03

以下のような情報をPHPでfetchAll(PDO::FETCH_ASSOC);しております。

php

1//$loansの内容 2Array 3( 4 [0] => Array 5 ( 6 [id] => 1 //mysqlの型:INT 7 [name] => loan_A //mysqlの型:STRING 8 [ttl] => 9000000000 //mysqlの型:BIGINT 9 [edate] => 2021-04-28 //mysqlの型:DATE 10 [mdate] => 2030-04-26 //mysqlの型:DATE 11 [type] => 変動 //mysqlの型:STRING 12 [spread] => 0.275 //mysqlの型:DOUBLE 13 ) 14 [1] => Array 15 ( 16 [id] => 2 //mysqlの型:INT 17 [name] => loan_B //mysqlの型:STRING 18 [ttl] => 5000000000 //mysqlの型:BIGINT 19 [edate] => 2022-04-28 //mysqlの型:DATE 20 [mdate] => 2031-04-26 //mysqlの型:DATE 21 [type] => //mysqlの型:STRING 22 [spread] => 0.222 //mysqlの型:DOUBLE 23 ) 24)

これをJavaScriptでオブジェクトとして利用してく以下のようにHTMLに出力することを考えました。

php

1//output.php 2<script type="text/javascript"> 3 var loans =<?=json_encode($loans,JSON_UNESCAPED_UNICODE)?>; 4</script>

Javascript

1var loans =[ 2{ 3id":1, 4"name":"Facility_057", 5"ttl":"9000000000",//here1 6"edate":"2021-04-28", 7"mdate":"2030-04-26", 8"type":"変動", 9"spread":0.27500000000000002220446049250313080847263336181640625//here2 10}, 11{ 12id":1, 13"name":"Facility_057", 14"ttl":"9000000000", 15"edate":"2022-04-28", 16"mdate":"2031-04-26", 17"type":null, 18"spread":0.2250000000000000055511151231257827021181583404541015625 19}

ここで、困っていることは//here1//here2の箇所になります。
0. //here1について
金額の桁数が大きいのでMYSQLINT型ではなくBIGINT型を指定しているのですが、json_encode()にかかわらず(var_dump($loans)したとしても)、STRING型PHPは出力してしまいます。これはこのような仕様で、INT型としてJavascriptで使いたいのであれば、Javascript側でmap()などを利用してそれぞれのオブジェクトの該当要素について、それぞれINT型にキャストしなければならないのでしょうか?

  1. //here2について

これは直接var_dump()echoをすれば素直に、入力桁数で返ってくるのに、json_encode()をすると、厳密な浮動小数点で返してこようとします。例えば$loans[0]['spread']であれば、"spread":0.275を返してくれればいいのですが、これも出力後、一定桁数をJavaScript側でMath.floor()等で一定の桁数を切らなければならないのでしょうか?。

そもそも、PHPの連想配列をJavaScriptのオブジェクトに変換したいならjson_encode()よりもっと良い方法がある等を含めてアドバイスを頂けますと嬉しいです。
宜しくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

BigIntはjsでも変換できますのでttlは文字列で受け取ってBigIntに変換すればいいでしょう
小数点以下はNumberで変換ができますが、演算時に精度の影響をうけるため
変換しても正確な演算をすることはできません。
演算に利用できないなら普通に文字列でもっておけばいいでしょう

php

1<?PHP 2$loans=[ 3 [ 4 "id" => 1 , 5 "name" => "loan_A" , 6 "ttl" => "9000000000" , 7 "edate" => "2021-04-28" , 8 "mdate" => "2030-04-26" , 9 "type" => "変動" , 10 "spread" => "0.27500000000000002220446049250313080847263336181640625" , 11 ], 12 [ 13 "id" => 2 , 14 "name" => "loan_B" , 15 "ttl" => "5000000000" , 16 "edate" => "2022-04-28" , 17 "mdate" => "2031-04-26" , 18 "type" => "", 19 "spread" => "0.2250000000000000055511151231257827021181583404541015625" , 20 ], 21 ]; 22print_r($loans); 23?> 24<script> 25var loans =<?=json_encode($loans,JSON_UNESCAPED_UNICODE)?>; 26loans.forEach(x=>x.ttl=BigInt(x.ttl)); 27console.log((loans[0]["ttl"])); 28</script>

投稿2021/10/08 04:36

編集2021/10/08 04:47
yambejp

総合スコア116724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

//here1について

doubleの精度は53ビットしかないので、巨大なBIGINTで異なる数が、doubleに変換したがゆえに同じになってしまうのを防ぐために、あえてこうなっている可能性があります。

//here2について

見た目はこうですが、データ的には0.275全く同じ(むしろ、人間が0.275と入力した場合、内部的には0.27500000000000002220446049250313080847263336181640625になる)です。

javascript

10.275 === 0.27500000000000002220446049250313080847263336181640625 // true

(0.5のような2進法でキリの良い数ばかりを使う場合を別として)浮動小数点数を使うときは、常に「どこで丸めるか」は考えておく必要があります。

投稿2021/10/08 04:10

maisumakun

総合スコア146018

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

SugiuraY

2021/10/08 04:27

なるほど、概ね理解することができました。ありがとうございます。 さて、では連想配列から出来上がった複数のJSのオブジェクトにおいて、これらのSTRING型の桁数の多い数字(here1)や内部的に受け付けた浮動小数点(here2)を意図した通り扱いたい場合には、map()などを使ってそれぞれNumber()でキャストしたり、Math.Floor()などで丸めようとしているところを指定して切り捨ててあげる、というやり方が一般的になるでしょうか?
SugiuraY

2021/10/08 04:29

というのも、例えば、JSではなくPHP段階でこれらを処理すべきですよという考え方や、そもそもjson_encode()でJSのオブジェクトへ変換するなんてできたとしてもやるんじゃない!等の意見があればとも思ったのですが、よくあるアプローチであれば、上記の通り、そのまま扱えない要素はキャストするなりしてきれいにして利用しようかと考えております。
maisumakun

2021/10/08 04:52

> これらのSTRING型の桁数の多い数字 こちらは使う側でハンドリングが必要です。JavaScript環境がサポートしているならbigintにしてもいいかもしれません(JSONにbigintは入れられません)。 > 内部的に受け付けた浮動小数点(here2) こちらは、特別な対応をする必要がないものです。極論、console.log(0.27500000000000002220446049250313080847263336181640625)が「0.275」という出力を返したりもします。
maisumakun

2021/10/08 04:53

> これは直接var_dump()やechoをすれば素直に、入力桁数で返ってくるのに、 実はこちらが「素直ではない」のです。適当な桁で丸めています。
SugiuraY

2021/10/08 06:12

ありがとうございます。 まずbigintの件ですが、調べたらNumberは17桁ほど行けるみたいで、これを超える場合はbigintを検討せよとのことでした。https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER 今回は、さすがにこれを超える可能性はなさそうなので、直にNumber型を使おうと思います。※すみませんところどころINT型を無差別に表現していましたが、厳密にJSの世界でプリミティブ型の中にはINT型というものは存在してませんでした。
SugiuraY

2021/10/08 06:22

一方浮動小数点の扱いなのですが、 例えば、loans[0].spread*100000000すると 27500000.000000004 をJSは返してきます。「機械」的にはこれが正しいのかもしれませんが、こちら側の意図する答えは「27500000」です。 この場合には、では何が正しいのかというと難しいお話なのですが、最終的な計算結果として得たいものは「27500000」です。 ともすれば対応不要とは仰いましたが、0.27500000000000002220446049250313080847263336181640625を得た段階で丸めるべきではないのでしょうか? それとも正確な計算という意味では、これを演算した結果の27500000.000000004を丸めるべきなのでしょうか?
maisumakun

2021/10/08 06:40

> この場合には、では何が正しいのかというと難しいお話なのですが、最終的な計算結果として得たいものは「27500000」です。 それは、もとの値が「0.275」と書かれていたとしても同じ結果です。浮動小数点数を使う上で「常に」考えないといけない、というのはそういう意味です。 > 0.27500000000000002220446049250313080847263336181640625を得た段階で丸めるべきではないのでしょうか? 丸めることは不可能です(コンピューターにとっては、0.275を2進法で表せる数字として「丸めた結果」が0.27500000000000002220446049250313080847263336181640625なのです)。
SugiuraY

2021/10/08 06:57

ありがとうございます。 >「常に」考えないといけない。 いやいや、そこをどうやって・・・と調べ始めたのですが、そんな単純な問題ではないことがようやっとわかりました! 桁数を上げてから計算してみたり、文字列かしてから計算してみたり、ライブラリが存在してみたり、なかなか一筋縄にはいかないことにようやくたどり着きました。 これらを調べてみて、自分の場合にはどうやったら誤差なく必要な値を得ることができるか手を動かしながら検討してみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問