PHP7.1 json_encode () ভাসা ইস্যু


93

এটি সচেতন হওয়ার বেশি হওয়ায় এটি কোনও প্রশ্ন নয়। আমি একটি অ্যাপ্লিকেশন আপডেট করেছি যা json_encode()পিএইচপি 7.1.1 ব্যবহার করে এবং আমি কখনও কখনও 17 ডিজিটের প্রসারিত করতে ভাসা পরিবর্তন করা একটি সমস্যা দেখছিলাম। ডকুমেন্টেশন অনুসারে, পিএইচপি 7.1.x serialize_precisionডাবল মানগুলিকে এনকোড করার সময় নির্ভুলতার পরিবর্তে ব্যবহার শুরু করেছে । আমি অনুমান করছি যে এটির একটি উদাহরণ মানের কারণ caused

472.185

হতে

472.18500000000006

যে মান পেরিয়ে যাওয়ার পরে json_encode()। আমার আবিস্কৃত হওয়ার পর আমি ফিরে পিএইচপি 7.0.16 রূপে ফিরিয়ে এবং আমি আর সঙ্গে সমস্যা আছে json_encode()। আমি পিএইচপি 7.0.16 এ ফিরে যাওয়ার আগে পিএইচপি 7.1.2 এ আপডেট করার চেষ্টা করেছি।

এই প্রশ্নের পিছনে যুক্তিটি পিএইচপি থেকে শুরু করে - ভাসমান সংখ্যা যথার্থতা , তবে এর শেষ কারণ হ'ল যথার্থতা থেকে ক্রিয়াকলাপের পরিবর্তে সিরিয়ালাইজ_প্রিপেসি ব্যবহার json_encode()

যদি কেউ এই সমস্যার সমাধানের বিষয়টি জানেন তবে আমি যুক্তি / সমাধানটি শুনে বেশি খুশি হব।

বহুমাত্রিক অ্যারে থেকে অংশ (আগে):

[staticYaxisInfo] => Array
                    (
                        [17] => stdClass Object
                            (
                                [variable_id] => 17
                                [static] => 1
                                [min] => 0
                                [max] => 472.185
                                [locked_static] => 1
                            )

                    )

এবং মধ্য দিয়ে যাওয়ার পরে json_encode()...

"staticYaxisInfo":
            {
                "17":
                {
                    "variable_id": "17",
                    "static": "1",
                    "min": 0,
                    "max": 472.18500000000006,
                    "locked_static": "1"
                }
            },

6
ini_set('serialize_precision', 14); ini_set('precision', 14);এটি সম্ভবত এটির আগের মতো সিরিয়ালাইজ করে তুলবে, তবে যদি আপনি সত্যিই আপনার ভাসা সম্পর্কিত কোনও নির্দিষ্ট নির্ভুলতার উপর নির্ভর করেন তবে আপনি কিছু ভুল করছেন।
apokryfos

4
"যদি কেউ এই সমস্যার সমাধান সম্পর্কে জানেন তবে" - কোন সমস্যা? আমি এখানে কোন সমস্যা দেখতে পাচ্ছি না। আপনি যদি পিএইচপি ব্যবহার করে জেএসএনকে ডিকোড করেন তবে আপনি এনকোড করা মানটি ফিরে পাবেন। এবং আপনি যদি কোনও ভিন্ন ভাষা ব্যবহার করে এটি ডিকোড করেন তবে সম্ভবত আপনি একই মান পাবেন। যে কোনও উপায়ে, আপনি যদি 12 অঙ্ক সহ মানটি মুদ্রণ করেন তবে আপনি মূল ("সঠিক") মানটি ফিরে পাবেন। আপনার অ্যাপ্লিকেশন দ্বারা ব্যবহৃত ভাসমানগুলির জন্য আপনার কি 12 দশকের বেশি সংখ্যার যথার্থতা প্রয়োজন?
axiac

12
@axiac 472.185! = 472.18500000000006। পার্থক্যের আগে এবং পরে একটি স্পষ্ট রয়েছে hisএটি একটি ব্রাউজারের কাছে একটি এজেএক্স অনুরোধের অংশ এবং মানটি এটির আসল অবস্থায় থাকা দরকার।
Gwi7d31

4
আমি শেষের পণ্যটি হাইচার্ট হওয়ায় স্ট্রিং রূপান্তরটি এড়াতে চেষ্টা করছি এবং এটি স্ট্রিং গ্রহণ করবে না। আমি মনে করি আমি এটি খুব অকার্যকর এবং ম্লান হিসাবে বিবেচনা করব যদি আপনি কোনও ফ্লোট মান গ্রহণ করেন, এটি স্ট্রিং হিসাবে নিক্ষেপ করেন, এটিকে প্রেরণ করেন এবং তারপরে জাভাস্ক্রিপ্ট স্ট্রিংটিকে পার্সফ্লোয়েট () দিয়ে ফ্লোটে ফিরিয়ে নিয়ে যায়। আপনি না?
Gwi7d31

4
@ অ্যাকিয়্যাক আমি লক্ষ করেছি যে আপনি পিএইচপি json_decode () আসল ভাসমান মানটি ফিরিয়ে আনবে। যাইহোক, যখন জাভাস্ক্রিপ্টটি JSON স্ট্রিংটিকে কোনও বস্তুর কাছে ফিরিয়ে দেয় তখন এটি মানটিকে 472.185 তে রূপান্তরিত করে না যেমন আপনার সম্ভাব্য ইনসিনুয়েটেড ছিল ... সুতরাং সমস্যাটি। আমি যা যাচ্ছি তা দিয়েই থাকব।
Gwi7d31

উত্তর:


97

অবশেষে আমি এই বাগটি খুঁজে না পাওয়া পর্যন্ত এটি আমাকে কিছুটা বাদ দিয়েছিল যা আপনাকে এই আরএফসির দিকে নির্দেশ করে যা বলেছে

বর্তমানে json_encode()EG (যথার্থতা) ব্যবহার করে যা 14 এ সেট করা হয়েছে That এর অর্থ হল 14 সংখ্যাটি সর্বাধিক সংখ্যাটি প্রদর্শন (মুদ্রণ) করার জন্য ব্যবহৃত হয়। আইইইই 754 ডাবল উচ্চতর নির্ভুলতা সমর্থন করে এবং serialize()/ var_export()ব্যবহার করে পিজি (সিরিয়ালাইজ_প্রিসিশন) যা আরও সুনির্দিষ্ট হতে ডিফল্ট হতে 17 সেট করে। যেহেতু json_encode()ইজি (নির্ভুলতা) ব্যবহার করে, json_encode()ভগ্নাংশের অংশের নিম্ন সংখ্যাগুলি সরিয়ে দেয় এবং মূল মানটি নষ্ট করে দেয় এমনকি পিএইচপি-এর ফ্লোট আরও সুনির্দিষ্ট ফ্লোট মান ধরে রাখতে পারে।

এবং (জোর আমার)

এই আরএফসি একটি নতুন সেটিং ইজি (স্পষ্টতা) = - 1 এবং পিজি (সিরিয়ালাইজ_প্রিসিশন) = - 1 প্রবর্তনের প্রস্তাব করেছে যা জেন্ড_ড্টোয়ার () এর মোড 0 ব্যবহার করে যা গোলাকার ফ্লোট সংখ্যাগুলির জন্য আরও ভাল অ্যালগরিদম ব্যবহার করে (-1 0 মোড নির্দেশ করতে ব্যবহৃত হয়)

সংক্ষেপে, পিএইচপি 7.1 json_encodeনতুন এবং উন্নত নির্ভুল ইঞ্জিনটি ব্যবহার করার একটি নতুন উপায় রয়েছে । ইন php.ini আপনি পরিবর্তন প্রয়োজন serialize_precisionথেকে

serialize_precision = -1

আপনি যাচাই করতে পারেন এটি এই কমান্ড লাইনের সাথে কাজ করে

php -r '$price = ["price" => round("45.99", 2)]; echo json_encode($price);'

আপনি পাওয়া উচিত

{"price":45.99}

G(precision)=-1এবং PG(serialize_precision)=-1 পিএইচপি 5.4
কিটিগার্ল

4
সঙ্গে সাবধান serialize_precision = -1। -1 সহ, এই কোডটি echo json_encode([528.56 * 100]);মুদ্রণ করে[52855.99999999999]
vl.lapikov

4
@ vl.lapikov যদিও এটি সাধারণ ভাসমান পয়েন্ট ত্রুটির মতো মনে হচ্ছে। এখানে একটি ডেমো রয়েছে , যেখানে আপনি এটি পরিষ্কারভাবে দেখতে পাচ্ছেন যে কোনও json_encodeসমস্যা নয়
মাচাভিটি

39

প্লাগইন বিকাশকারী হিসাবে আমার কোনও সার্ভারের php.ini সেটিংসে সাধারণ অ্যাক্সেস নেই। সুতরাং, মাচাভিটির উত্তরের ভিত্তিতে আমি এই ছোট্ট কোডের কোডটি লিখেছি যা আপনি আপনার পিএইচপি স্ক্রিপ্টে ব্যবহার করতে পারেন। এটি কেবল স্ক্রিপ্টের উপরে রাখুন এবং json_encode যথারীতি কাজ করতে থাকবে।

if (version_compare(phpversion(), '7.1', '>=')) {
    ini_set( 'serialize_precision', -1 );
}

কিছু ক্ষেত্রে এটি আরও একটি পরিবর্তনশীল সেট করা প্রয়োজন। আমি এটি দ্বিতীয় সমাধান হিসাবে যুক্ত করছি কারণ আমি নিশ্চিত নই যে দ্বিতীয় সমাধানটি সব ক্ষেত্রেই কার্যকর হয় যেখানে প্রথম সমাধানটি কাজ প্রমাণিত করেছে।

if (version_compare(phpversion(), '7.1', '>=')) {
    ini_set( 'precision', 17 );
    ini_set( 'serialize_precision', -1 );
}

4
আপনার প্লাগইনটি বিকাশকারী অ্যাপ্লিকেশনটির বাকি অংশগুলির জন্য অপ্রত্যাশিত সেটিংস পরিবর্তন করতে পারে with তবে, আইএমও, আমি নিশ্চিত না যে এই বিকল্পটি কীভাবে ধ্বংসাত্মক হতে পারে ...
LOL

সচেতন হন যে পরিবর্তনের যথার্থ মান (দ্বিতীয় উদাহরণ) আপনার অন্যান্য গাণিতিক ক্রিয়াকলাপগুলিতে আরও বড় প্রভাব ফেলতে পারে। php.net/manual/en/ini.core.php#ini.precision
রিকার্ডো মার্টিনস

@ রিকার্ডোমার্টিনস: ডকুমেন্টেশন অনুসারে ডিফল্ট যথার্থতা 14 হয় fix তুমি কি একমত?
আলেভ

@ আলেভ আমি যা বলছিলাম তা হ'ল কেবল সিরিয়ালাইজ_প্রার্থনা পরিবর্তন করা যথেষ্ট এবং আপনার অ্যাপ্লিকেশন যে অভিজ্ঞতা ব্যবহার করতে পারে তার অন্যান্য পিএইচপি আচরণের সাথে আপস করবেন না
রিকার্ডো মার্টিনস

4

আমি আর্থিক মানগুলি এনকোড করেছিলাম এবং 330.46এন্ডোডিংয়ের মতো জিনিস ছিল 330.4600000000000363797880709171295166015625। আপনি যদি পিএইচপি সেটিংস পরিবর্তন করতে না চান বা না করতে পারেন এবং আপনি ডেটা কাঠামো আগে থেকেই জানেন তবে খুব সহজ সমাধান রয়েছে যা আমার পক্ষে কাজ করেছিল। কেবল এটিকে একটি স্ট্রিংয়ে ফেলে দিন (নিম্নলিখিত উভয়ই একই কাজ করে):

$data['discount'] = (string) $data['discount'];
$data['discount'] = '' . $data['discount'];

আমার ব্যবহারের ক্ষেত্রে এটি ছিল একটি দ্রুত এবং কার্যকর সমাধান। কেবলমাত্র নোট করুন যে এর অর্থ আপনি যখন JSON থেকে এটিকে আবার ডিকোড করবেন তখন এটি একটি স্ট্রিং হবে কারণ এটি ডাবল উদ্ধৃতিতে আবৃত হবে।


4

আমি যথার্থতা এবং সিরিয়ালাইজ_প্রিফিশন উভয়কে একই মান (10) এ সেট করে সমাধান করেছি:

ini_set('precision', 10);
ini_set('serialize_precision', 10);

আপনি আপনার php.ini এ এটি সেট করতে পারেন


3

আমার একই সমস্যা ছিল তবে কেবল সিরিয়ালাইজ_প্রিভিশন = -1 সমস্যার সমাধান করেনি। 14 থেকে 17 পর্যন্ত যথার্থতার মান আপডেট করতে আমাকে আরও একটি পদক্ষেপ করতে হয়েছিল (এটি আমার পিএইচপি 7.0 ইনআই ফাইলটিতে সেট করা হয়েছিল) do স্পষ্টতই, এই সংখ্যার মান পরিবর্তন করা গণিত ফ্লোটের মান পরিবর্তন করে।


3

অন্যান্য সমাধানগুলি আমার পক্ষে কার্যকর হয়নি। আমার কোড প্রয়োগের শুরুতে এখানে আমাকে যা যুক্ত করতে হয়েছিল তা এখানে:

if (version_compare(phpversion(), '7.1', '>=')) {
    ini_set( 'precision', 17 );
    ini_set( 'serialize_precision', -1 );
}

এটি কি মূলত আলিন পপের উত্তরের মতো নয়?
igorsantos07

1

আমার পক্ষে সমস্যাটি তখন ছিল যখন JSON_NUMERIC_CHECK দ্বিতীয় আর্গুমেন্ট হিসাবে json_encode () পাশ করেছে, যা সমস্ত সংখ্যাকে টাইপ করে (কেবল পূর্ণসংখ্যার নয়)


1

স্ট্রিং হিসাবে এটি ব্যবহার করে আপনার প্রয়োজনীয় নির্ভুলতার সাথে স্ট্রিং হিসাবে সংরক্ষণ করুন number_format, তারপরে json_encodeএটি JSON_NUMERIC_CHECKবিকল্পটি ব্যবহার করে :

$foo = array('max' => number_format(472.185, 3, '.', ''));
print_r(json_encode($foo, JSON_NUMERIC_CHECK));

তুমি পাও:

{"max": 472.185}

নোট করুন যে এটি আপনার উত্স অবজেক্টের সমস্ত সংখ্যক স্ট্রিংকে ফলাফলপ্রাপ্ত জেএসএনে সংখ্যা হিসাবে এনকোড করার জন্য পাবে।


4
আমি এটি পিএইচপি 7.3 এ পরীক্ষা করেছি এবং এটি কার্যকর হয় না (আউটপুটটিতে এখনও খুব উচ্চ নির্ভুলতা রয়েছে)। স্পষ্টতই JSON_NUMERIC_CHECK পতাকাটি পিএইচপি broken.১
ফিলিপ

0
$val1 = 5.5;
$val2 = (1.055 - 1) * 100;
$val3 = (float)(string) ((1.055 - 1) * 100);
var_dump(json_encode(['val1' => $val1, 'val2' => $val2, 'val3' => $val3]));
{
  "val1": 5.5,
  "val2": 5.499999999999994,
  "val3": 5.5
}

0

দেখে মনে হচ্ছে সমস্যাটি যখন ঘটে serializeএবং serialize_precisionবিভিন্ন মানকে সেট করা হয়। আমার ক্ষেত্রে যথাক্রমে 14 এবং 17। উভয়কে 14 এ সেট করার ফলে সেটিংয়ের মতোই সমস্যার সমাধান হয়েছেserialize_precision করা -1-এ করার ।

এর ডিফল্ট মানটি serialize_precision পিএইচপি 7.1.0 হিসাবে -1 এ পরিবর্তিত হয়েছিল যার অর্থ "এই জাতীয় সংখ্যার বৃত্তাকার জন্য একটি বর্ধিত অ্যালগরিদম ব্যবহার করা হবে"। তবে আপনি যদি এখনও এই সমস্যাটি ব্যবহার করে থাকেন তবে এটি হতে পারে কারণ আপনার কোনও পূর্ববর্তী সংস্করণ থেকে পিএইচপি কনফিগারেশন ফাইল রয়েছে। (আপনি আপগ্রেড করার সময় আপনি নিজের কনফিগারেশন ফাইলটি রেখেছিলেন?)

আরেকটি বিষয় বিবেচনা করতে হবে তা যদি আপনার ক্ষেত্রে ভাসমান মানগুলি ব্যবহার করার জন্য বোধগম্য হয়। দশমিক জায়গাগুলির যথাযথ সংখ্যাটি সর্বদা আপনার জেএসএন-এ বজায় রাখা হয় তা নিশ্চিত করার জন্য আপনার সংখ্যাগুলি সহ স্ট্রিং মানগুলি ব্যবহার করা বোধগম্য বা নাও থাকতে পারে।


-1

Json_encode () এর আগে আপনি [সর্বাধিক] => 472.185 ফ্লোট থেকে স্ট্রিং ([সর্বোচ্চ] => '472.185') এ পরিবর্তন করতে পারেন) যেহেতু জসন যেভাবেই একটি স্ট্রিং, আপনার ভাসমান মানকে json_encode () এর আগে স্ট্রিংগুলিতে রূপান্তর করা আপনার মানটি বজায় রাখবে।


এটি প্রযুক্তিগতভাবে একটি নির্দিষ্ট পরিমাণে সত্য, তবে খুব অদক্ষ। যদি কোনও জেএসএন স্ট্রিংয়ের কোনও ইনট / ফ্লোট উদ্ধৃত না হয় তবে জাভাস্ক্রিপ্ট এটিকে একটি প্রকৃত ইন্ট / ফ্লোট হিসাবে দেখতে পাবে। আপনার উপস্থাপনা সম্পাদন আপনাকে প্রতিটি একক মান একবার ব্রাউজারের দিকে একবার ইন্ট / ফ্লোটে ফেলে দিতে বাধ্য করে। অনুরোধ অনুযায়ী এই প্রকল্পে কাজ করার সময় আমি প্রায়শই 10000+ মানগুলি নিয়ে কাজ করি। প্রচুর ব্লাট প্রসেসিংয়ের অবসান ঘটত।
Gwi7d31

আপনি যদি কোথাও ডেটা প্রেরণের জন্য জেএসএন ব্যবহার করছেন, এবং একটি সংখ্যা প্রত্যাশিত তবে আপনি একটি স্ট্রিং প্রেরণ করেন, এটি কাজের গ্যারান্টিযুক্ত নয়। প্রেরণ অ্যাপ্লিকেশনটির বিকাশকারী গ্রহণযোগ্য অ্যাপ্লিকেশনটির নিয়ন্ত্রণ রাখে না এমন পরিস্থিতিতে এটি কোনও সমাধান নয়।
অসুলিক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.