كيف يمكنني "تقليم" A C# إلى القيمة التي سيتم تخزينها كما في قاعدة بيانات SQLite؟

StackOverflow https://stackoverflow.com/questions/4200736

سؤال

لقد لاحظت أنه عندما أقوم بتخزين قيمة مزدوجة مثل EG x = 0.56657011973046234 في قاعدة بيانات SQLite ، ثم استرجعها لاحقًا ، أحصل عليها y = 0.56657011973046201. بحسب ال SQLITE Spec و ال .NET Spec (لم أزعجني في الأصل قراءة :) هذا متوقع وطبيعي.

مشكلتي هي أنه على الرغم من أن الدقة العالية ليست مهمة ، فإن تطبيقي يتعامل مع المستخدمين الذين يقومون بإدخال/اختيار الزوجي الذي يمثل معلومات ثلاثية الأبعاد أساسية ، ثم تشغيل عمليات المحاكاة عليها للعثور على نتيجة. ويمكن حفظ هذا الإدخال في قاعدة بيانات SQLite لإعادة تحميلها وإعادة تشغيلها لاحقًا.

يحدث الارتباك لأن سلسلة من المدخلات التي تم إنشاؤها حديثًا ستتم محاكاة بطريقة مختلفة قليلاً عن تلك المدخلات نفسها بمجرد تخزينها وإعادة تحميلها (كما تغيرت القيم المزدوجة). هذا منطقي ، ولكن ليس مرغوبًا.

لم أتوصل إلى شروط حول كيفية التعامل مع هذا ، لكن في غضون ذلك ، أود أن أقصر/تشوش إدخال المستخدم على القيم التي يمكن تخزينها بالضبط في قاعدة بيانات SQLite. لذلك إذا قام المستخدم بإدخال 0.56657011973046234, ، يتم تحويله بالفعل إلى 0.56657011973046201.

ومع ذلك ، لم أتمكن من معرفة ، بالنظر إلى رقم ، ما هي القيمة التي سيتم تخزينها في قاعدة البيانات ، وهي أقل من تخزينها واستعادتها بالفعل من قاعدة البيانات ، والتي تبدو مجزأة. هل هناك طريقة راسخة للقيام بذلك؟

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

المحلول

يتمتع Round Double بتنفيذ مع معلمة تحدد عدد الأرقام. استخدم هذا إلى جولة إلى 14 رقمًا (على سبيل المثال) مع: rval = math.round (val ، 14)

ثم جولة عند تلقي القيمة من قاعدة البيانات ، وفي بداية عمليات المحاكاة ، أي. إذن في تطابق القيم؟

للتفاصيل:

http://msdn.microsoft.com/en-us/library/75ks3aby.aspx

فكر آخر إذا كنت لا تقارن القيم في قاعدة البيانات ، فقط تخزينها: لماذا لا تخزنها ببساطة كبيانات ثنائية؟ ثم سيتم تخزين جميع البتات واستردادها حرفيًا؟

نصائح أخرى

قد تكون الإجابة هي تخزين القيم المزدوجة كأسلاك أرقام مهمة. انظر إلى الفرق بين كيفية معالجة SQLite أرقام حقيقية مقابل النص (سأوضح مع واجهة سطر الأوامر ، من أجل البساطة):

sqlite> create table t1(dr real, dt varchar(25));
sqlite> insert into t1 values(0.56657011973046234,'0.56657011973046234');
sqlite> select * from t1;
0.566570119730462|0.56657011973046234

إن تخزينه بتقارب حقيقي هو سبب مشكلتك - SQLite يمنحك فقط تقريب 15 رقمًا. إذا قمت بدلاً من ذلك بتخزينه كنص ، فيمكنك استرداد السلسلة الأصلية باستخدام برنامج C# وتحويله إلى المزدوج الأصلي.

على افتراض أن كلا من SQL Lite و .NET ينفذون بشكل صحيح مواصفات IEEE ، يجب أن تكون قادرًا على الحصول على نفس النتائج الرقمية إذا استخدمت نفس نوع النقطة العائمة على كلا الجانبين (لأنه لا ينبغي تغيير القيمة عند تمريرها من قاعدة البيانات إلى C# والعكس صحيح).

أنت تستخدم حاليًا نقطة عائمة 8-بايت IEEE (واحدة) (*) في SQL Lite ونقطة عائمة 16 بايت في C# (مزدوج). ال float اكتب في C# يتوافق مع معيار IEEE 8 بايت ، لذلك باستخدام هذا النوع بدلاً من double يمكن أن يحل المشكلة.

(*) توثق SQL Lite أن Real هو قيمة نقطة عائمة ، مخزنة كرقم عائم 8 بايت IEEE.

يمكنك استخدام سلسلة لتخزين # في DB. أنا شخصياً فعلت ما اقترحه Winwaed من التقريب قبل التخزين وبعد الجلب من DB (الذي استخدم Numeric ()).

أتذكر أنني محترق من قبل المصرفيين ، لكن قد يكون ذلك مجرد مواصفات.

يمكنك تخزين المزدوج كسلسلة ، وباستخدام تنسيق الرحلة المستديرة عند تحويل المزدوج إلى سلسلة ، يتم ضمان توليد نفس القيمة عند تحليلها:

string formatted = theDouble.ToString("R", CultureInfo.Invariant);

إذا كنت تريد أن تتجه قيم الإدخال العشرية ، فعليك تقييدها على 15 رقمًا مهمًا. إذا كنت تريد أن تكون قيم الفاصلة المزدوجة ذات الدقة المزدوجة SQLite ، فقد تكون محظوظًا ؛ يتطلب ذلك الطباعة إلى 17 رقمًا على الأقل ، ولكن من ما يمكنني قوله ، يقوم SQLite بطباعتها إلى 15 بحد أقصى (تعديل: ربما يمكن لخبير sqlite تأكيد هذا؟ لقد قرأت للتو الكود المصدري وتتبعه - كنت على صواب ، فإن الدقة تقتصر على 15 رقمًا.)

لقد اختبرت مثالك في واجهة أمر SQLite على Windows. لقد أدرجت 0.56657011973046234 ، وحددت 0.566570119730462. في C ، عندما قمت بتعيين 0.566570119730462 إلى مزدوج وطبعت إلى 17 رقمًا ، حصلت على 0.56657011973046201 ؛ هذه هي نفس القيمة التي تحصل عليها من C#. 0.56657011973046234 و 0.56657011973046201 خريطة لأرقام مختلفة عائمة ، لذلك ، وبعبارة أخرى ، فإن SQLite Double لا يدور حوله.

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