سؤال

أحافظ على نص Python الذي يستخدم xlrd لاسترداد القيم من جداول بيانات Excel ، ثم القيام بأشياء مختلفة معها. بعض الخلايا في جدول البيانات هي أرقام عالية الدقة ، ويجب أن تظل على هذا النحو. عند استرداد قيم إحدى هذه الخلايا ، xlrd يعطيني float مثل 0.38288746115497402.

ومع ذلك ، أحتاج إلى الحصول على هذه القيمة في سلسلة لاحقًا في الكود. القيام بهما str(value) أو unicode(value) سيعود شيئًا مثل "0.382887461155". تقول المتطلبات أن هذا غير مقبول ؛ يجب الحفاظ على الدقة.

لقد جربت أمرين حتى الآن بلا نجاح. الأول كان استخدام سلسلة تنسيق:

data = "%.40s" % (value) 
data2 = "%.40r" % (value) 

لكن كلاهما ينتج نفس الرقم المستدير ، "0.382887461155".

عند البحث عن الأشخاص الذين يعانون من مشاكل مماثلة في ذلك وأماكن أخرى على الإنترنت ، كان هناك اقتراح مشترك هو استخدام Decimal صف دراسي. لكن لا يمكنني تغيير الطريقة التي يتم بها إعطاء البيانات لي (ما لم يعرف أحدهم طريقة سرية xlrd إرجاع عشرية). وعندما أحاول القيام بذلك:

data = Decimal(value)

أحصل على TypeError: Cannot convert float to Decimal. First convert the float to a string. لكن من الواضح أنني لا أستطيع تحويلها إلى سلسلة ، وإلا سأفقد الدقة.

لذا ، نعم ، أنا منفتح على أي اقتراحات - حتى تقارير جسيمة/اختراق حقًا إذا لزم الأمر. أنا لست من ذوي الخبرة بشكل رهيب مع Python (أكثر من رجل Java/C# بنفسي) لذا لا تتردد في تصحيحي إذا كان لدي نوع من سوء الفهم الأساسي هنا.

تحرير: فقط أعتقد أنني سأضيف أنني أستخدم Python 2.6.4. لا أعتقد أن هناك أي متطلبات رسمية تمنعني من تغيير الإصدارات ؛ يجب أن لا تعبث أيًا من الكود الآخر.

هل كانت مفيدة؟

المحلول

أنا مؤلف XLRD. هناك الكثير من الالتباس في إجابات وتعليقات أخرى لدحضها في التعليقات ، لذلك أقوم بذلك في إجابة.

katrielex: "" "الدقة التي تضيع في شجاعة XLRD" "" --- لا أساس لها من الصحة وغير صحيح. تقوم XLRD بإعادة إنتاج تعويم 64 بت بالضبط الذي يتم تخزينه في ملف XLS.

katrielex: "" "قد يكون من الممكن تعديل تثبيت XLRD المحلي لتغيير طاقم العائم" "--- لا أعرف لماذا تريد القيام بذلك ؛ أنت لا تفقد أي دقة من خلال تطفو عدد صحيح 16 بت !!! في أي حال ، يتم استخدام هذا الرمز فقط عند قراءة ملفات Excel 2.x (التي كان لها سجل خلية من نوع INTEGER). لا يعطي OP أي مؤشر على أنه يقرأ مثل هذه الملفات القديمة.

jloubert: يجب أن تكون مخطئا. "%.40r" % a_float هو مجرد طريقة باروك للحصول على نفس الإجابة مثل repr(a_float).

everybody: لا تحتاج إلى تحويل تعويم إلى عشري للحفاظ على الدقة. بيت القصيد من repr() الوظيفة هي أن ما يلي مضمون:

float(repr(a_float)) == a_float

Python 2.x (x <= 6) reper يعطي 17 رقمًا عشريًا من الدقة ، لأن ذلك مضمون لإعادة إنتاج القيمة الأصلية. في وقت لاحق ، تعطي Pythons (2.7 ، 3.1) الحد الأدنى من الأرقام العشرية التي ستؤدي إلى إعادة إنتاج القيمة الأصلية.

Python 2.6.4 (r264:75708, Oct 26 2009, 08:23:19) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.38288746115497402'
>>> float(repr(f)) == f
True

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
>>> f = 0.38288746115497402
>>> repr(f)
'0.382887461154974'
>>> float(repr(f)) == f
True

لذا فإن خلاصة القول هي ذلك إذا كنت تريد سلسلة تحافظ على كل دقة كائن تعويم ، فاستخدم preserved = repr(the_float_object) ... استرداد القيمة لاحقًا float(preserved). بكل بساطة. لا حاجة ل decimal وحدة.

نصائح أخرى

يمكنك استخدام repr() للتحويل إلى سلسلة دون فقدان الدقة ، ثم التحويل إلى عشرية:

>>> from decimal import Decimal
>>> f = 0.38288746115497402
>>> d = Decimal(repr(f))
>>> print d
0.38288746115497402

تحرير: أنا مخطئ. سأترك هذه الإجابة هنا ، لذا فإن بقية الخيط منطقي ، لكن هذا ليس صحيحًا. يرجى الاطلاع على إجابة جون ماشين أعلاه. شكرا يا رفاق =).

إذا كانت الإجابات أعلاه تعمل بشكل رائع - فسيوفر لك الكثير من القرصنة السيئة. ومع ذلك ، على الأقل على نظامي ، لن يفعلوا ذلك. يمكنك التحقق من ذلك باستخدام EG

import sys
print( "%.30f" % sys.float_info.epsilon )

هذا الرقم هو أصغر تعويم يمكن أن يميز نظامك عن الصفر. أي شيء أصغر من ذلك يمكن إضافته أو طرحه بشكل عشوائي من أي تعويم عند إجراء عملية ما. هذا يعني أنه على الأقل في إعداد بيثون ، تضيع الدقة داخل الشجاعة xlrd, ، ويبدو أن هناك شيئًا يمكنك القيام به دون تعديله. وهو أمر غريب كنت أتوقع أن تحدث هذه القضية من قبل ، ولكن على ما يبدو لا!

قد يكون من الممكن تعديل محليك xlrd التثبيت لتغيير float يقذف. افتح site-packages\xlrd\sheet.py والنزول إلى السطر 1099:

...
elif rc == XL_INTEGER:
                    rowx, colx, cell_attr, d = local_unpack('<HH3sH', data)
                    self_put_number_cell(rowx, colx, float(d), self.fixed_BIFF2_xfindex(cell_attr, rowx, colx))
...

لاحظ ال float يلقي - يمكنك محاولة تغيير ذلك إلى أ decimal.Decimal وانظر ماذا يحدث.

تعديل: تم مسح إجابتي السابقة ب/ج أنها لم تنجح بشكل صحيح.

أنا على Python 2.6.5 وهذا يعمل بالنسبة لي:

a = 0.38288746115497402
print repr(a)
type(repr(a))    #Says it's a string

ملاحظة: هذا فقط يتحول إلى سلسلة. ستحتاج إلى التحويل إلى Decimal نفسك لاحقًا إذا لزم الأمر.

كما قيل بالفعل ، فإن التعويم ليس دقيقًا على الإطلاق - لذا فإن الحفاظ على الدقة قد يكون مضللاً إلى حد ما.

إليك طريقة لإخراج كل جزء آخر من المعلومات من كائن تعويم:

>>> from decimal import Decimal
>>> str(Decimal.from_float(0.1))
'0.1000000000000000055511151231257827021181583404541015625'

طريقة أخرى سيكون مثل ذلك.

>>> 0.1.hex()
'0x1.999999999999ap-4'

تمثل كلا السلاسل المحتويات الدقيقة للطفو. كل أي شيء آخر يفسر التعويم حيث يعتقد بيثون أنه ربما كان المقصود (وهو ما هو في معظم الوقت صحيح).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top