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

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

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

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

5回答

2737閲覧

Django 変数に15桁以上の数値を格納したい 他

jupiter

総合スコア8

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/08/08 07:49

編集2018/08/10 08:24

前提・実現したいこと

・入力した数値データを計算し、その結果をファイルに出力するプログラムを作成したい。(質問箇所は入力部分のみ)
・変数に15桁以上の数値を格納したい

発生している問題・エラーメッセージ

・139.66713225333334 という値を入力した際に 139.667132253333 のように丸め込まれてしまう
・入力データを用いて計算するのに数値型で辞書に保存したいのだがstr型で格納される

###サンプルコード(元のプログラムと少し変更ありだが、ほぼ同じ)
views.py

from django.shortcuts import render from django.http import HttpResponse from .forms import HelloForm def index(request): params = { 'form': HelloForm() } if request.method == 'POST': number = request.POST['number'] attr = dict() attr['number'] = number return render(request, 'app/index.html', params)

forms.py

from django import forms class HelloForm(forms.Form): number = forms.DecimalField( label='number', max_digits=30, decimal_places=20 )

index.html

<!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>hello</title> </head> <body> <form action="{% url 'index' %}" method="post"> {% csrf_token %} {{ form }} <input type="submit" value="click"> </form> </body> </html>

補足情報

{'number':139.66713225333334} と値を格納したいが
{'number':'139.667132253333'}と格納されている状態。
↑数値の後半が丸め込まれている。 
↑数値に''が付いている。

データベースの問題なのでしょうか…。ちなみにデータベースについてはテンプレート作成時にアプリを追加したのみで全くいじっておりません。(SQLiteのまま)

※モデルの定義はなし

ご回答いただけると幸いです。
※前別サイトにて質問した際、一応DecimalFieldを使えば可能といわれたのですが、上手くいかないのは何故でしょうか。
※request.POST を表示すると
QueryDict:{'…':['…'],'number':['139.667132253333']}

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

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

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

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

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

guest

回答5

0

ベストアンサー

この記事が参考になりますね。
decimal.Decimal型は、整数、文字列、タプルから作ることができます
【Python3】Decimalモジュールを使った、精度の高い小数点以下の数値計算

こっちでもDecimalFieldが文字列になるって言ってる人がいますね。
encode/django-rest-framework

あと関係ないかもしれないんですが
Python : 整数最大値、辞書項目数の最大値
DecimalFieldの数値が整数なら19桁までなんでしょうか?
そうなるとdecimal_places=14だったらmax_digits=19とかまでなんでしょうか?どなか教えていただきたい。

投稿2018/08/09 10:19

編集2018/08/09 10:44
grilled_python

総合スコア237

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

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

jupiter

2018/08/10 00:51

ご回答ありがとうございます。いまだ解決できていないのですが、Decimalモジュールについてもう少し勉強してみようと思います^^
grilled_python

2018/08/12 03:33 編集

djangoが原因ではなくおっしゃる通りsqliteが原因の様です。 正確性を保つためには(mysqlなどを使う場合はCharFieldではなく)DecimalFieldは使うべきとも書いています。 https://stackoverflow.com/questions/38538773/django-float-or-decimal-are-rounded-unintentionally-when-saving sqliteにdecimal型がなく、float型になっているのが原因のようですので、対策として考えられるのは 1.sqliteではなくmysqlなどを使ってdecimal型で保存する 2.sqliteのまま使う場合はy_waiwai様が回答の様に整数として扱って処理する。 どちらかではないでしょうか ちなみに小数点以下を実際に保存して操作する必要があるならsqlite3は使うべきではないとされているようです。
jupiter

2018/08/16 08:25

何度も回答ありがとうございます。本日もモデルを使用し、かつデータベースをmysqlに変更しやってみたのですが、やはり同じ現象が起こってしまいました…。簡易なものでも、DecimalFieldが機能しているDjangoアプリを拝見したいものです…。一緒に検討していただき本当に感謝申し上げます。
jupiter

2018/08/17 02:37 編集

確認したところテーブルの型はdecimalになっており、作成したwebから入力すると15桁で切れてしまう(残り2桁が00となる)のですが、データベースにおいてinsert into構文を用い直接入力すると max_digits=17, decimal_places=14 の値が入力できます。
grilled_python

2018/08/17 09:38 編集

モデルで保存してないのであればDBは関係ないでしょうし、printで確認すると丸まってない様に思えるのですが。もしよろしければ確認方法と式を載せて頂ければと思います
jupiter

2018/08/17 10:17

自分でもごちゃごちゃになってきているので、来週再度質問をあげなおしたいと思います。 ①DBの問題だと別サイトで助言を頂く(sqlite使用) ②models.pyおよびDBを使用しないverを作成(上のコード) →DBを使用していないはずなのに、値が丸まってしまう ③DBを別のものに変更した上で(mysql)で、DB・models.pyを使用したverを作成(4つ上のコメント) ※models.DecimalField使用 ④データベースを確認したところテーブルの型はdecimalになっている(2つ上のコメント) ⑤ブラウザの入力フォームから値を入れ、DBを確認すると値が丸まっている というのが今までのおおまかな流れです。 本当に丁寧に回答していただきありがとうございます。ご縁があれば、またあげなおしますので付き合っていただけると幸いです。
guest

0

コメントだと答えずらいのでまとめますね。
まず、DBのせいではありません。忘れてください。

まず丸め誤差については分かりやすいサイトでお調べしてください。
とにかく小数点以下が長いと丸められます。

num15 = 1 + 0.000000000000001 #小数点以下が15桁 num16 = 1 + 0.0000000000000001 #小数点以下が16桁 print(num15) #1.000000000000001 #丸められない print(num16) #1.0 #丸められる

なのでDecimalFieldやDecimalモジュールを使います。
decimalは数字で長い小数点以下を計算すると誤差が出るから文字列の様に扱って正しく計算して表示できるようにするものです。

from decimal import Decimal num17 = Decimal("0.00000000000000001") #小数点以下17桁 num17 = 1 + num17 print(num17) # 1.000000000000000010000000000 print(type(num17)) #<class 'decimal.Decimal'> num18 = 1 + 0.000000000000000001 print(type(num18)) # 1.0 # <class 'float'> #丸まってしまうのはfloat型だからです。type()で確認してみるとどこで間違っているか分かりやすいかもしれません。

投稿2018/08/17 11:30

編集2018/08/17 11:48
grilled_python

総合スコア237

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

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

0

number = forms.CharField() に変更し
views.py でfloat型に変更することで15桁以上の値を入力することができました。

しかし、DecimalFieldを使った正確な入力はいまだできておりません。

投稿2018/08/10 08:22

jupiter

総合スコア8

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

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

0

models.DecimalField(139.66713225333334, max_digits=17, decimal_places=14)

よく見たらmodelsではなかったですね。失礼しました。

投稿2018/08/09 06:57

編集2018/08/09 08:01
grilled_python

総合スコア237

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

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

0

小数点以下の数値というのは扱いが難しいです。
浮動少数点数にはそれだけの精度はないので、15桁以上となると、整数に変換して処理するしか無いです

{'number':139.66713225333334} と値を格納したいが

というなら、その文字列からコンマを抜いて、'13966713225333334'という整数にして処理しましょう
#以後の処理で *1000000000000000 の数値だと意識しないといけませんが

投稿2018/08/08 08:18

y_waiwai

総合スコア87747

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問