Skip to content
العودة إلى المدوّنة
دروس تعليمية

دليل تحويل درجات الحرارة: صيغ سيلزيوس وفهرنهايت وكلفن ورانكن

صيغ دقيقة لتحويل درجات الحرارة بين سيلزيوس وفهرنهايت وكلفن ورانكن، مع أمثلة برمجية بخمس لغات وأنماط APIs وجداول مرجعية جاهزة.

15 دقائق للقراءة

أطلقتَ لوحة طقس يوم الاثنين، وبحلول الأربعاء فتح مستخدم من تورنتو تقريرَ خلل: التطبيق يعرض درجة الحرارة الخارجية بالقيمة 284. كانت نقطة نهاية OpenWeatherMap تُرجع القيم بوحدة Kelvin افتراضياً، وكانت واجهة المستخدم تتوقع سيلزيوس، ولم يتحقق أحد في المنتصف. عملية طرح واحدة ناقصة، ولقطة شاشة محرجة على Twitter.

إن كنتَ تريد الصيغتين الأساسيتين فقط والمضيّ في طريقك:

  • صيغة سيلزيوس إلى فهرنهايت: °F = °C × 9/5 + 32
  • صيغة فهرنهايت إلى سيلزيوس: °C = (°F − 32) × 5/9
  • سيلزيوس إلى كلفن: K = °C + 273.15

تغطّي هذه الصيغ الثلاث نحو 90% من احتياجات المطوّرين الفعلية. وما تبقّى من هذا الدليل هو الـ10% الأخرى: من أين جاء العامل 9/5؟ ولماذا لا تظهر قيمة Kelvin سالبة أبداً؟ وكيف تجعل نظام الأنواع في لغتك يرفض celsiusToFahrenheit(kelvinValue) أثناء التصريف؟ وكيف تتجنّب شحن خلل تورنتو مرة أخرى؟ يمكنك أيضاً تخطّي القراءة كلياً واستخدام محوّل درجات الحرارة لدينا حين تحتاج قيمة رقمية الآن. أما لتحويلات الوحدات خارج نطاق الحرارة، فراجع الدليل الشامل لتحويل الوحدات الأوسع.

لماذا تختلف درجة الحرارة عن سائر تحويلات الوحدات؟

معظم تحويلات الوحدات علاقة خطيّة بسيطة تمرّ بالصفر. المتر الواحد يساوي 3.28084 قدم، وانتهى. ضاعِف الأمتار تتضاعف الأقدام، وصفر من الأمتار هو صفر من الأقدام. يمكنك بناء مكتبة تحويل بثابت ضرب واحد لكل زوج وحدات، ثم تنسى الأمر.

درجة الحرارة تكسر هذا النموذج بنقطة جوهرية واحدة: مقاييسها لا تشترك في نقطة الصفر. فـCelsius يضع صفره عند نقطة تجمّد الماء، وFahrenheit عند خليط ملحيّ يعود إلى عام 1724، وKelvin عند الحدّ النظري الأدنى في الديناميكا الحرارية. للانتقال بين أيّ مقياسين تحتاج إلى معامل تدريج وإزاحة معاً. فدرجة الحرارة تحويل تآلفيّ (affine) لا خطيّ.

لهذا نتيجة عمليّة خطِرة: قيم درجة الحرارة غير قابلة للجمع كما تُجمَع قيم الطول أو الكتلة. فـ 20°C + 20°C لا تساوي 40°C بأيّ معنى فيزيائيّ، ولا يمكنك “جمع غرفتين” لتحصل على غرفة أدفأ. في المقابل، يمكنك إضافة فرق درجات حرارة إلى قيمة درجة حرارة، لأنّ الفروق خطيّة فعلاً. هذا بالضبط ما أوقع حادثة Medeva للقاحات في المملكة المتحدة عام 2006، حين خلط جهاز تسجيل في سلسلة التبريد بين القراءة المطلقة والفرق، فوسَم آلاف الجرعات بأنّها خارج المواصفات. الكمّيّات الكثافيّة (intensive) كدرجة الحرارة تحتاج دوماً إلى هذا الحاجز الذهنيّ: الأرقام التي تتشارك الوحدة لا تتشارك بالضرورة قواعد الجبر.

المقاييس الأربعة لدرجة الحرارة

مقياسان فقط يهمّان في البرمجة اليوميّة (Celsius وFahrenheit)، والثالث يهمّ في أيّ شيء علميّ (Kelvin)، والرابع يظهر في مكان واحد فقط: كتب الديناميكا الحرارية الأمريكية وقواعد أكواد التكييف التي ما زالت تُحيل إليها.

سيلزيوس (°C)

نَشَر Anders Celsius مقياسه عام 1742، وكان في الأصل 0° عند الغليان و100° عند التجمّد، أي مقلوباً عمّا نستخدمه اليوم. أمّا الاتجاه الحديث، مع 0°C عند نقطة تجمّد الماء و100°C عند نقطة غليانه تحت ضغط جوّيّ قياسيّ، فترسّخ بعد وفاته بقليل. وهو اليوم الوحدة المشتقّة من النظام الدوليّ لدرجة الحرارة اليوميّة، والمقياس الافتراضيّ في كل بلد عدا الولايات المتحدة والبهاما وبليز وجزر كايمان وليبيريا.

ربطت إعادة تعريف النظام الدوليّ عام 2019 مقياس Celsius بـKelvin ربطاً صارماً: فصار 0°C معرَّفاً بدقّة بـ 273.15 K. ونقطة تجمّد الماء التي كانت قبلاً هي التعريف، صارت اليوم نتيجة مَقيسة (تقع ضمن 0°C بفارق أجزاء من المليون، لكنّها لم تعد المرساة).

فهرنهايت (°F)

اقترح Daniel Gabriel Fahrenheit مقياسه عام 1724، واختار 0°F نقطة تجمّد خليط ملحيّ بعينه، وهي أبرد درجة حرارة أمكنه إعادة إنتاجها بموثوقية في شتاء دانزيغ، وجعل 96°F درجة حرارة الجسم. ثم دفعت المعايرةُ اللاحقة مقابل نقطتَي تجمّد الماء النقيّ وغليانه درجةَ حرارة الجسم إلى 98.6°F، ووضعت نقطة التجمّد عند 32°F ونقطة الغليان عند 212°F، بمدًى قدره 180 درجة.

لا يزال Fahrenheit قائماً في الولايات المتحدة للطقس والطبخ والاستخدام الطبّي. وأحياناً يُدافَع عن مدى الـ180 درجة بين التجمّد والغليان (مقابل 100 في Celsius) بأنّه يتيح “دقّة أعلى في درجات الحرارة المحيطة”، وهو ادّعاء هامشيّ، لكنّه يفسّر لماذا تُعلَّم منظِّمات الحرارة الأمريكية بخطوات 1°F بينما تستخدم الأوروبية عادةً خطوات 0.5°C.

كلفن (K)

اقترح William Thomson، اللورد Kelvin، مقياساً مطلقاً عام 1848. وصار Kelvin الحديث الوحدةَ الأساس في النظام الدوليّ لدرجة الحرارة. وربطت إعادة تعريف النظام الدوليّ عام 2019 الكلفن بثابت بولتزمان k_B = 1.380649 × 10⁻²³ J/K ربطاً دقيقاً، فصار كمّيّة معرَّفة لا مَقيسة.

في Kelvin ثلاث غرائب يجب على المطوّرين معرفتها:

  1. لا رمز للدرجة. اكتب 300 K لا 300°K؛ هذا عرف النظام الدوليّ منذ 1967.
  2. يبدأ من الصفر المطلق. 0 K = −273.15°C، ولا يُفترض بك رؤية قيمة Kelvin سالبة في بيانات صحيحة أبداً، فعامِلها على أنّها خطأ إدخال.
  3. حجم الدرجة نفسه في Celsius. تغيّر قدره 1 K يساوي تغيّراً قدره 1°C، وفروق درجات الحرارة قابلة للتبادل بينهما. تختلف فقط القيم المطلقة بمقدار الإزاحة 273.15.

Kelvin هو الخيار الصحيح كلّما ضربتَ درجات حرارة أو قسمتَها، من إشعاع حراريّ (T⁴) إلى قانون الغاز المثاليّ وفيزياء الجسم الأسود. القسمة على قيمة Celsius سالبة أو قريبة من الصفر تُفجّر علاقات فيزيائية تريدها عادة أن تبقى منتهية.

رانكن (°R)

اقترح William Rankine هذا المقياس عام 1859 بوصفه المكافئ الفهرنهايتيّ لـKelvin: مقياس مطلق، صفره عند الصفر المطلق، لكن بدرجات بحجم درجة Fahrenheit. فـ 0°R = −459.67°F، و491.67°R = 0°C.

لن تصادف Rankine تقريباً خارج الهندسة الحرارية الأمريكية، من حسابات التكييف إلى تكرير النفط وتحليل احتراق محرّكات الصواريخ، حيث تحتاج الحسابات إلى مقياس مطلق مع ورود بيانات الإدخال بـFahrenheit. التحويل آليّ: °R = °F + 459.67، أو ما يكافئها °R = K × 9/5. ومعظم برمجيّات الهندسة الحديثة قادرة على الاحتفاظ بـKelvin داخلياً والتحويل للعرض فقط، وهذا ما أنصح به متى كان لك الخيار.

صيغ تحويل درجة الحرارة (الاتجاهات الستّة كاملةً)

ستّة اتجاهات وأربعة مقاييس وستّ صيغ. عملياً، تحفظ الصيغ المرتكزة على Celsius، ثم تُركّب الباقي.

سيلزيوس إلى فهرنهايت وبالعكس

°F = °C × 9/5 + 32
°C = (°F − 32) × 5/9

العامل 9/5 هو نسبة مديَي المقياسين بين المَعلمتين الفيزيائيّتين نفسهما. من التجمّد إلى الغليان، يغطّي Fahrenheit 180 درجة (من 32 إلى 212)، بينما يغطّي Celsius 100 (من 0 إلى 100)، و180 / 100 = 9/5 = 1.8. أمّا + 32 فهي الإزاحة اللازمة لمحاذاة صفرَي نقطة التجمّد، لأنّ صفر Fahrenheit يقع بمقدار 32°F تحت صفر Celsius.

مثال تطبيقيّ: °F = 25 × 9/5 + 32 = 45 + 32 = 77°F.

سيلزيوس إلى كلفن وبالعكس

K = °C + 273.15
°C = K − 273.15

لا تدريج، إزاحة فقط. قيمة 273.15 هي المسافة العدديّة من صفر Celsius (نقطة تجمّد الماء) نزولاً إلى الصفر المطلق، مقيسة بدرجات Celsius. وبما أنّ Kelvin وCelsius يتشاركان حجم الدرجة نفسه، فلا يوجد معامل ضرب.

فهرنهايت إلى كلفن وبالعكس

K = (°F − 32) × 5/9 + 273.15
°F = (K − 273.15) × 9/5 + 32

لا توجد صيغة أقصر، لأنّ تغيير المقياس والإزاحة معاً مطلوبان. في الكود، المرور عبر Celsius أنظفَ غالباً: k = cToK(fToC(f)). ستكتب أقلّ، وتثق بها أكثر، وسيُحسِّن المصرِّف التركيب بعيداً عنك على أيّ حال.

تحويلات رانكن

°R = °F + 459.67
°F = °R − 459.67
°R = K × 9/5
K  = °R × 5/9
°R = °C × 9/5 + 491.67

قيمة 491.67 تساوي 32 × 9/5 + 459.67، أي قيمة Rankine المقابلة لـ 0°C. نادراً ما تُركّب هذه الصيغ في العمل. ومتى احتجتَ Rankine فعلاً، عامِلها على أنّها “التوأم المطلق لـFahrenheit”، ومُرَّ عبر Fahrenheit أو Kelvin.

من أين جاء العامل 9/5؟ اشتقاق سريع

يرتبط المقياسان بدالّة تآلفيّة °F = a × °C + b. ولحلّ a وb تحتاج إلى نقطتَي معايرة معروفتين. نقطة التجمّد ونقطة الغليان هما الزوج التقليديّ:

  • التجمّد: 0°C ↔ 32°F
  • الغليان: 100°C ↔ 212°F

عوِّض كلتيهما في °F = a × °C + b:

32  = a × 0   + b   →  b = 32
212 = a × 100 + 32  →  a = (212 − 32) / 100 = 180 / 100 = 9/5

هذا كلّ شيء: معادلتان خطّيّتان ومجهولان، فتسقط عليك كامل عمليّة التحويل. الحدس الهندسيّ: تخيّل ميزاني حرارة عموديَّين جنباً إلى جنب، أحدهما بـCelsius والآخر بـFahrenheit. ميزان Fahrenheit مشدود عموديّاً (بميل 9/5) ومرفوع إلى الأعلى (بمقطع 32) نسبةً إلى ميزان Celsius. وتقع كلّ قيمة تحويل أخرى على هذا الخطّ المشدود المُزاح.

الاشتقاق نفسه بنقطتَي (0°C, 273.15 K) و(100°C, 373.15 K) يعطيك سيلزيوس-إلى-كلفن: ميل 1 ومقطع 273.15. والاشتقاق نفسه بأيّ نقطتَي معايرة لا لبس فيهما يعطيك أيّ تحويل تآلفيّ. لا شيء رياضيّاً مميّز في درجة الحرارة، بل التعقيد كلّه في إعداد نقطتَي المرساة الذي لا تحتاجه أنواع الوحدات الأخرى.

نقطة التقاطع −40°: قاعدة ذاكرة مفيدة

هل هناك درجة حرارة تقرأها Celsius وFahrenheit بالقيمة ذاتها؟ اجعل °C = °F في صيغة التحويل:

°C = °C × 9/5 + 32
°C − °C × 9/5 = 32
°C × (1 − 9/5) = 32
°C × (−4/5) = 32
°C = −40

فـ −40°C = −40°F بالضبط. نقطة تقاطع واحدة فقط، وتصادف أنّها درجة حرارة حقيقية قد تواجهها في Yellowknife أو Yakutsk أو Fairbanks في يناير. وهي أيضاً فحص ذهنيّ زهيد الكلفة: كلّما رمقتَ بعينك تحويلاً بين C وF فرأيت النتيجة قرب −40، يجب أن يكون الرقمان متقاربَين. فإن قال أحدهما −40°C والآخر −72°F، فلديك خلل في الاتجاه.

أحتفظ بقائمة القواعد الذهنيّة الكاملة ملصقة إلى جانب شاشتي: التجمّد (0 / 32)، ودرجة حرارة الجسم (37 / 98.6)، ودرجة حرارة الغرفة (20 / 68)، والغليان (100 / 212)، و−40 (−40 / −40). خمس نقاط تُغطّي كل فحوص السلامة التي أحتاجها تقريباً.

تحويل درجة الحرارة في الكود

الصيغ بسيطة، لكنّ ضبطها في شيفرة حقيقيّة يتعلّق غالباً بأمرَين: منع المُستدعي من تمرير Fahrenheit حيث تريد Celsius، وجعل سلوك الفاصلة العائمة قابلاً للتنبّؤ عند الحدود (التجمّد، الصفر المطلق، حرارة الأفران). كل مثال أدناه برنامج كامل قابل للتشغيل.

JavaScript / TypeScript

في JavaScript الساذج، تحصل على تحويلات دالّيّة فوراً:

const cToF = (c) => c * 9 / 5 + 32;
const fToC = (f) => (f - 32) * 5 / 9;
const cToK = (c) => c + 273.15;
const kToC = (k) => k - 273.15;
const fToK = (f) => cToK(fToC(f));
const kToF = (k) => cToF(kToC(k));
const cToR = (c) => (c + 273.15) * 9 / 5;
const rToC = (r) => r * 5 / 9 - 273.15;

console.log(cToF(100));   // 212
console.log(fToC(98.6));  // 37
console.log(kToC(300));   // 26.85

وتتيح لك TypeScript جعل خلط الوحدات خطأً في وقت التصريف بوسم نوع الرقم:

type Scale = 'C' | 'F' | 'K' | 'R';
type Temp<S extends Scale> = number & { readonly __scale: S };

const t = <S extends Scale>(value: number, _scale: S): Temp<S> =>
  value as Temp<S>;

const cToF = (c: Temp<'C'>): Temp<'F'> => t(c * 9 / 5 + 32, 'F');
const fToC = (f: Temp<'F'>): Temp<'C'> => t((f - 32) * 5 / 9, 'C');

const indoor = t(22, 'C');
const outdoor = cToF(indoor);   // سليم: Temp<'F'>
// const broken = cToF(outdoor); // خطأ تصريف: Temp<'F'> ليس Temp<'C'>

الأنواع الموسومة بلا كلفة عند التشغيل، وتكلّفك نحو عشرة أسطر من الصيغة النمطيّة. وبالمقابل، يصير خلل تورنتو في الفقرة الافتتاحيّة خطّاً أحمرَ متموّجاً في محرّرك.

Python

الدوالّ العاديّة تعمل جيّداً، لكنّ Enum مع dataclass يُسدِّد ثمنه أوّل مرّة تُسجّل فيها درجة حرارة:

from dataclasses import dataclass
from enum import Enum

class Scale(Enum):
    C = "°C"
    F = "°F"
    K = "K"
    R = "°R"

@dataclass(frozen=True)
class Temperature:
    value: float
    scale: Scale

    def to(self, target: Scale) -> "Temperature":
        c = _to_celsius(self)
        return _from_celsius(c, target)

    def __str__(self) -> str:
        return f"{self.value:.2f}{self.scale.value}"

def _to_celsius(t: Temperature) -> float:
    if t.scale is Scale.C: return t.value
    if t.scale is Scale.F: return (t.value - 32) * 5 / 9
    if t.scale is Scale.K: return t.value - 273.15
    if t.scale is Scale.R: return (t.value - 491.67) * 5 / 9
    raise ValueError(f"مقياس غير معروف: {t.scale}")

def _from_celsius(c: float, scale: Scale) -> Temperature:
    if scale is Scale.C: return Temperature(c, scale)
    if scale is Scale.F: return Temperature(c * 9 / 5 + 32, scale)
    if scale is Scale.K: return Temperature(c + 273.15, scale)
    if scale is Scale.R: return Temperature(c * 9 / 5 + 491.67, scale)
    raise ValueError(f"مقياس غير معروف: {scale}")

body = Temperature(37, Scale.C)
print(body.to(Scale.F))   # 98.60°F
print(body.to(Scale.K))   # 310.15K

إن كنتَ تعالج بيانات علمية يكون فيها 0.1 + 0.2 != 0.3 مسألة تدقيق حسابيّ، فاستبدل float بـ decimal.Decimal. المقابل هو السرعة (Decimal أبطأ بنحو 50 ضعفاً)، إضافةً إلى أنّ 5/9 لا تمثيل عشريّاً دقيقاً لها، فتحتاج إلى Decimal(5) / Decimal(9) بسياق مضبوط. في معظم خطوط بيانات المستشعرات، يكفي float مع round(value, 2) عند حدّ العرض.

Go

يتيح لك نظام أنواع Go تجاوز ما تُقدّمه TypeScript: نوع float64 مسمّى لا يمكن خلطه بصمت بنوع float64 مسمّى آخر، حتى لو اشتركا في التمثيل ذاته وقت التشغيل.

package main

import "fmt"

type Celsius float64
type Fahrenheit float64
type Kelvin float64
type Rankine float64

func (c Celsius) ToFahrenheit() Fahrenheit { return Fahrenheit(c*9/5 + 32) }
func (c Celsius) ToKelvin() Kelvin         { return Kelvin(c + 273.15) }
func (f Fahrenheit) ToCelsius() Celsius    { return Celsius((f - 32) * 5 / 9) }
func (k Kelvin) ToCelsius() Celsius        { return Celsius(k - 273.15) }
func (f Fahrenheit) ToKelvin() Kelvin      { return f.ToCelsius().ToKelvin() }

func main() {
    room := Celsius(22)
    fmt.Printf("%.2f °F\n", room.ToFahrenheit()) // 71.60 °F
    fmt.Printf("%.2f K\n", room.ToKelvin())      // 295.15 K

    // var bug Fahrenheit = room          // خطأ تصريف
    // fmt.Println(room.ToKelvin() + 1)   // خطأ تصريف: Kelvin + int غير مُصنَّف يستلزم Kelvin(1)
}

الكلفة نحو سطر لكل مقياس، والفائدة أنّ ToFahrenheit لا يمكن أن يقبل قيمة Kelvin بالخطأ، وأنّ دالّة تأخذ Celsius سترفض float64 خاماً عند موضع الاستدعاء.

Rust

يمنحك نمط newtype في Rust الضمانات نفسها التي في Go، إضافةً إلى تحويلات From/Into زهيدة:

#[derive(Clone, Copy, Debug, PartialEq)]
struct Celsius(f64);

#[derive(Clone, Copy, Debug, PartialEq)]
struct Fahrenheit(f64);

#[derive(Clone, Copy, Debug, PartialEq)]
struct Kelvin(f64);

impl From<Celsius> for Fahrenheit {
    fn from(c: Celsius) -> Self { Fahrenheit(c.0 * 9.0 / 5.0 + 32.0) }
}

impl From<Fahrenheit> for Celsius {
    fn from(f: Fahrenheit) -> Self { Celsius((f.0 - 32.0) * 5.0 / 9.0) }
}

impl From<Celsius> for Kelvin {
    fn from(c: Celsius) -> Self { Kelvin(c.0 + 273.15) }
}

impl From<Kelvin> for Celsius {
    fn from(k: Kelvin) -> Self { Celsius(k.0 - 273.15) }
}

fn main() {
    let body = Celsius(37.0);
    let body_f: Fahrenheit = body.into();
    let body_k: Kelvin = body.into();
    println!("{:.2} {:?} {:?}", body.0, body_f, body_k);
    // 37.00 Fahrenheit(98.6) Kelvin(310.15)
}

يمكنك إضافة طبقة تحقّق فوق ذلك: فـ TryFrom<f64> for Kelvin الذي يرفض القيم السالبة يُعيد Result<Kelvin, TemperatureError> ويدفع الفحص إلى وقت الإنشاء، فلا تصل الحالات غير الصالحة أبداً إلى منطق الأعمال.

SQL (PostgreSQL)

خزِّن درجات الحرارة مع قيود CHECK، واشتقّ الوحدات البديلة بوصفها أعمدة مولَّدة. بهذه الطريقة تصير قيمة Kelvin السالبة انتهاكَ قيدٍ عند الإدراج، لا خللاً صامتاً في البيانات يظهر بعد ثلاث استعلامات.

CREATE OR REPLACE FUNCTION c_to_f(c numeric) RETURNS numeric AS $$
    SELECT c * 9.0 / 5.0 + 32.0;
$$ LANGUAGE SQL IMMUTABLE;

CREATE OR REPLACE FUNCTION c_to_k(c numeric) RETURNS numeric AS $$
    SELECT c + 273.15;
$$ LANGUAGE SQL IMMUTABLE;

CREATE TABLE sensor_readings (
    id          bigserial PRIMARY KEY,
    recorded_at timestamptz NOT NULL DEFAULT now(),
    celsius     numeric(6, 2) NOT NULL,
    fahrenheit  numeric(6, 2) GENERATED ALWAYS AS (c_to_f(celsius)) STORED,
    kelvin      numeric(6, 2) GENERATED ALWAYS AS (c_to_k(celsius)) STORED,
    CONSTRAINT  kelvin_non_negative CHECK (celsius >= -273.15)
);

INSERT INTO sensor_readings (celsius) VALUES (22.5), (0), (100);
SELECT celsius, fahrenheit, kelvin FROM sensor_readings;
-- 22.50 | 72.50  | 295.65
--  0.00 | 32.00  | 273.15
-- 100.00| 212.00 | 373.15

-- يُرفَض عند الإدراج:
-- INSERT INTO sensor_readings (celsius) VALUES (-300);
-- ERROR: new row for relation "sensor_readings" violates check constraint

GENERATED ALWAYS AS ... STORED تقايض قليلاً من مساحة القرص مقابل سرعة وقت الاستعلام، إذ تقرأ القيمة دون إعادة حسابها. أمّا لجداول إنترنت الأشياء عالية الحجم، فاستبدل STORED بعرض (view) إن كان ضغط القرص يهمّك أكثر من زمن القراءة.

التعامل مع APIs الطقس وإنترنت الأشياء

أشيع الأخطاء الإنتاجيّة مع درجة الحرارة ليس خطأ صيغة، بل عدم توافق الوحدات بين ما تُرجعه API وما تعرضه واجهتك. جولة سريعة على الموفّرين الذين يصادفهم معظم المطوّرين:

OpenWeatherMap تُرجع Kelvin افتراضياً. مرِّر units=metric لـCelsius، أو units=imperial لـFahrenheit. النقطة الحاسمة: إن نسيتَ معامل الاستعلام، حصلتَ على Kelvin. وأرقام مثل 284.15 تصل في حقل اسمه temp قد خدعت من المهندسين ما يكفي لاستحقاق اختبار تكامل.

Open-Meteo تُرجع Celsius افتراضياً وتقبل temperature_unit=fahrenheit. لا خيار لـKelvin، فهي ليست API علميّة.

Tomorrow.io و**WeatherAPI** تتوخّيان النظام المتريّ افتراضياً، لكنّهما تُعيدان المقياسين في الاستجابة ذاتها تحت مفاتيح مختلفة. اقرأ المفتاح الذي تُشير إليه شيفرتك فعلاً، لا جاره.

النمط الذي أستخدمه لأيّ عملية استقبال بيانات طقس أو مستشعرات:

type Reading = {
  value: number;
  scale: 'C' | 'F' | 'K';
  source: string;
};

function normalise(raw: Reading): number /* سيلزيوس */ {
  switch (raw.scale) {
    case 'C': return raw.value;
    case 'F': return (raw.value - 32) * 5 / 9;
    case 'K': return raw.value - 273.15;
  }
}

// عند الاستقبال، تحمل كلّ قراءة مقياسها صراحةً.
// طبقة الواجهة لا تُخمّن، بل تستهلك سيلزيوس وتُنسّق وفق تفضيل المستخدم.

من هنا تتفرّع قاعدتان:

  1. كلّ حدّ استقبال يُسجّل مقياس المصدر. لا أرقام مجرّدة تعبر حدود الوحدات.
  2. طبقة العرض هي المكان الوحيد الذي يُحوّل إلى الوحدة المفضّلة للمستخدم.

التحويل المزدوج، حيث “تُطبِّع” طبقتان الرقم معاً، هو الخلل الشائع الآخر. فريق الخلفيّة يُحوّل Kelvin إلى Celsius عند الكتابة، وفريق الواجهة، دون أن يدري، يطبّق - 273.15 نفسها عند القراءة. فيرى المستخدمون درجات حرارة نحو −251°C. الحلّ هو مالكٌ واحد للتطبيع، لا مزيد من الاختبارات.

في إنترنت الأشياء، غالباً ما تصل بيانات المستشعر الخام بوصفها عدّ ADC ينبغي تحويله إلى درجة حرارة عبر منحنى معايرة (ولترمستور NTC بقيمة 10kΩ يعني ذلك معادلة Steinhart–Hart). ثم تأتي تحويلات مقياس درجة الحرارة بعد ذلك على القيمة المعايَرة. خلط المرحلتين هو ما يُنتج أرقاماً “تبدو” كدرجات حرارة لكنّها منحرفة بنسبة 30%.

الأخطاء الشائعة وكيفية تجنّبها

هذه الأخطاء الستّة تظهر في شيفرات إنتاجيّة حقيقية. قِس شيفرتك عليها مباشرة.

استخدام اتجاه الصيغة الخطأ

أشيع عرَض: تطبيق يعرض حمّى رضيع بقيمة 37°C ثم يُؤشّرها حرجة. ما حدث فعلاً أنّ API أعادت 37°F، ووسَمَها أحدٌ بأنّها celsius لأنّ اسم العمود قال ذلك، ثمّ قارن منطق العتبات الطبّية القيمة بمقياس Celsius. تجنّب ذلك بجعل النوع هو الذي يحمل الوحدة، لا اسم المتغيّر.

معاملة درجة الحرارة كمّيّةً امتداديّة

averageTemperature له معنى، أمّا sumTemperatures فلا. فإن كان استعلام التجميع لديك يحتوي SUM(temperature_c)، فثمّة خطأ. الأرجح أنّك تريد AVG، أو في حالات نادرة مقياساً مُتكاملاً من نوع درجة-يوم. درجة الحرارة كمّيّة كثافيّة، فلا تجمع اثنتين منها متوقّعاً نتيجة ذات معنى.

تقريب الفاصلة العائمة

في JavaScript، تعطي (37 * 9 / 5) + 32 قيمة 98.60000000000001 لا 98.6. وكل لغة تستخدم ثنائيّات دقّة IEEE 754 تسلك السلوك نفسه. الخيارات:

  • العرض بـ toFixed(2) (أو ما يقابلها في لغتك) والتوقّف عند هذا الحدّ.
  • استخدام مكتبة عشريّة (decimal.js، Python Decimal، BigDecimal) لدقّة بمستوى التدقيق.
  • التخزين كأعداد صحيحة بوحدة عُشر الدرجة (370 بدل 37.0) والقسمة على 10 عند العرض فحسب.

في عرض الواجهة، يكفي toFixed(2) غالباً. أمّا في نظام فوترة أو نظام تنظيميّ تتراكم فيه أخطاء التقريب، فاستعمل العشريّات.

كلفن سالب في التحقق من المدخلات

Kelvin غير سالب بموجب قانون فيزيائيّ. فطلب بجسم { "tempK": -10 } غير صالح دائماً. افرض ذلك عند الحدّ — JSON schema، Pydantic، Zod، قيد CHECK — لا في عمق منطق الأعمال. الاستثناء الوحيد، أنظمة الكمّ ذات “درجة الحرارة المطلقة السالبة”، لا يُصادف في أيّ API يُرجَّح أن تتكامل معها؛ وإن صادفته، ستعرف ذلك سلفاً.

غياب تسميات الوحدات في الواجهة والسجلّات

سطر سجلّ يقول sensor 42: 37 عديم الفائدة بعد ستّة أشهر. أهي Celsius؟ أم Fahrenheit؟ أم عدّ ADC خامّ؟ اكتب دائماً sensor 42: 37°C، أو هيكِل السطر هكذا: { "sensor": 42, "value": 37, "unit": "celsius" }. مساحة القرص رخيصة، أمّا فرز الأعطال الإنتاجيّة في الثالثة فجراً فليس كذلك.

اختلاط المنطقة الزمنيّة بدرجة الحرارة

تطلق تطبيقات السفر هذا الخلل أحياناً: حين يعبر المستخدم منطقة زمنيّة، “يُزيح” الكود بلطف كل حقل موسوم بطابع زمنيّ، بما في ذلك قراءات درجة الحرارة. درجة الحرارة لا تأبه للمناطق الزمنيّة. فـالطابع الزمنيّ على القراءة يحتاج منطق منطقة زمنيّة، أمّا قيمة القراءة فلا. احفظهما في حقلين منفصلين، ومرِّرهما عبر خطَّي تحويل منفصلَين.

اختصارات الحساب الذهنيّ

حين لا يكون لديك محوّل مفتوح.

سيلزيوس إلى فهرنهايت (تقريب): ضاعِف القيمة ثمّ أضف 30. فـ 20°C → 70°F (الفعلي 68)، و30°C → 90°F (الفعلي 86). دقّة في حدود 2–3°F عبر 0–40°C، وهي تقريباً كل درجة حرارة تشعر بها خارج فرن الفخّار.

فهرنهايت إلى سيلزيوس (تقريب): اطرح 30 ثمّ انصِّف. فـ 80°F → 25°C (الفعلي 26.7)، و60°F → 15°C (الفعلي 15.6). بحزام الدقّة نفسه.

سيلزيوس إلى كلفن: أضف 273 وقرِّب. تخسر 0.15 K، وهي أدنى من دقّة الميزان لأيّ شيء خارج مختبر فيزياء.

مرساتان تستحقّان الحفظ: 20°C = 68°F ≈ 293 K، و 100°C = 212°F = 373.15 K. من هاتين، يُقرّبك الاستكمال الخطّيّ بما يكفي لأيّ تقدير.

تغطّي القواعد السريعة السفرَ والطبخ التقريبيّ ونشرات الطقس. أمّا لأيّ شيء يدخل الكود أو تقريراً تنظيمياً، فاستعمل الصيغ الدقيقة، أو افتح أداة تحويل درجات الحرارة المجانية لدينا وانسخ القيمة الدقيقة.

جداول مرجعيّة

درجات الحرارة اليوميّة

السياقسيلزيوسفهرنهايتكلفن
مجمّد منزليّ−18°C0°F255.15 K
نقطة التجمّد0°C32°F273.15 K
ثلّاجة4°C39°F277.15 K
درجة حرارة الغرفة20°C68°F293.15 K
درجة حرارة الجسم37°C98.6°F310.15 K
عتبة الحمّى38°C100.4°F311.15 K
يوم صيف حارّ35°C95°F308.15 K
غليان الماء100°C212°F373.15 K

تحويلات الطبخ والأفران

إعداد الفرنسيلزيوسفهرنهايت
طبخ منخفض / بطيء125°C257°F
خَبز دافئ150°C302°F
خَبز معتدل175°C347°F
خَبز قياسيّ (الكعك)180°C356°F
تحمير190°C374°F
تحمير ساخن200°C392°F
تحمير عالي220°C428°F
بيتزا / قشرة خبز250°C482°F

تقرِّب الوصفات الأمريكية 350°F إلى 175°C أو 180°C بحسب الكتاب؛ والقيمة الدقيقة هي 176.67°C. أيّ اختيار مناسب، فأفران المنازل نادراً ما تثبّت الحرارة بأفضل من ±5°C على أيّ حال.

القيم القصوى العلميّة

الظاهرةكلفنسيلزيوس
الصفر المطلق (الحدّ النظريّ الأدنى)0 K−273.15°C
الخلفيّة الكونيّة الميكروويّة2.725 K−270.425°C
الهيليوم السائل (غليان، 1 atm)4.2 K−268.95°C
انتقال فائق التوصيل (YBCO)93 K−180.15°C
النيتروجين السائل (غليان)77 K−196.15°C
ظلّ الفضاء العميق~40 K~−233°C
الثلج الجاف (تسامي)194.65 K−78.5°C
سطح الشمس5,778 K5,504.85°C
نواة الشمس1.57×10⁷ K1.57×10⁷ °C*
بلازما Tokamak (هدف ITER)1.5×10⁸ K~1.5×10⁸ °C*

*عند هذه المقاديم، تصير إزاحة 273.15 K خطأ تقريب، ويقرأ Celsius وKelvin القيمة ذاتها فعلياً.

أسئلة شائعة

ما صيغة تحويل سيلزيوس إلى فهرنهايت؟

اضرب Celsius في 9/5 (أو 1.8) ثمّ أضف 32: °F = °C × 9/5 + 32. فمثلاً 25°C × 1.8 + 32 = 77°F. يعكس معامل الضرب نسبة 180:100 بين مدَي المقياسين من التجمّد إلى الغليان، وتحاذي الـ 32 صفرَيهما المختلفَين.

ما صيغة تحويل فهرنهايت إلى سيلزيوس؟

اطرح 32 من قيمة Fahrenheit ثمّ اضرب في 5/9: °C = (°F − 32) × 5/9. فلقيمة 72°F الحساب (72 − 32) × 5/9 = 40 × 5/9 ≈ 22.22°C. اطرح أوّلاً ثمّ اضرب، فعكس الترتيب يعطي إجابة خطأ.

عند أيّ درجة حرارة تتساوى سيلزيوس وفهرنهايت؟

عند −40 درجة بالضبط. جعل °C = °F في صيغة التحويل يعطي °C = °C × 9/5 + 32، وحلّها °C = −40. وهي نقطة الحرارة الوحيدة التي يقرأ فيها المقياسان القيمة نفسها، ومَعْلَم مفيد لفحص السلامة سواء لموجات البرد الواقعيّة أو لأخطاء اتجاه التحويل.

كيف أحوّل 350°F إلى سيلزيوس للخَبز؟

350°F تعادل نحو 176.67°C. تُقرِّب الوصفات الأوروبيّة هذا عادةً إلى 180°C، وتستخدم كثير من جداول التحويل الأمريكية-المتريّة قيمة 175°C. كلاهما يعمل في فرن منزليّ، فاستقرار درجة الحرارة في هذا النطاق أسوأ من خطأ التقريب. استعمل أداة محوّل درجات الحرارة للقيم الدقيقة حين تهمّ الدقّة.

كم يساوي 100°F بالسيلزيوس؟

100°F ≈ 37.78°C. أعلى قليلاً من درجة حرارة الجسم الطبيعية (37°C / 98.6°F)، وتُعدّ أحياناً بداية حمّى خفيفة. غير أنّ الإرشادات الطبّية تعتمد عادةً 38°C / 100.4°F عتبة حقيقية للحمّى، فـ 100°F على الحدّ لكنّها ليست ذات دلالة سريريّة بعد.

لماذا الصفر المطلق −273.15°C وليس −273 فقط؟

لأنّ إعادة تعريف النظام الدوليّ عام 2019 ثبَّتت ثابت بولتزمان بدقّة، فصار −273.15°C القيمة الدقيقة المحسوبة للصفر المطلق بدل تقريب مُدوَّر. قبل 2019 كان صفر Celsius مرتبطاً بالنقطة الثلاثيّة للماء، وكانت الـ 0.15 تأتي من القياس. أمّا اليوم فهي دقيقة بالتعريف.

متى ينبغي استخدام كلفن بدل سيلزيوس في الكود؟

في كل مرّة تضرب فيها درجة حرارة أو تقسم أو ترفعها إلى قوّة: إشعاع الجسم الأسود (T⁴)، وحسابات الغاز المثالي، ومعدّلات التفاعل. Kelvin لا يكون سالباً أبداً، فتبقى القسمة مستقرّة. أمّا فروق درجة الحرارة فيتبادلان فيها Celsius وKelvin (تغيّر بخمس درجات هو نفسه في كليهما).

هل لا تزال رانكن مستخدمة في 2026؟

نعم، لكن على نطاق ضيّق. لا تزال الهندسة الميكانيكيّة والتكييف والفضاء الأمريكيّة تستخدم Rankine في تحليل الدورات الديناميكية الحرارية حين تكون كل المدخلات الأخرى بـFahrenheit. خارج هذه الحقول وخارج الولايات المتحدة، هو ميّت فعلياً. فإن كنتَ تكتب برمجيّات عامّة، فدعم Rankine تأمين زهيد، لكنّه نادراً ما يحمل وزناً فعلياً.

كيف أحوّل درجة الحرارة في استعلام SQL؟

ضمِّن الصيغة مباشرةً أو استعمل عموداً من نوع GENERATED ALWAYS AS. مثال: SELECT celsius * 9.0 / 5.0 + 32.0 AS fahrenheit FROM readings. تجبر الـ 9.0 و5.0 (لا 9 و5) حسابَ الفاصلة العائمة في معظم اللهجات، وإلّا فالقسمة الصحيحة ستقطع بصمت. وأضف CHECK (celsius >= -273.15) لرفض القيم العبثيّة عند الإدراج.

ما أيسر طريقة لتحويل سيلزيوس إلى فهرنهايت ذهنيّاً؟

ضاعف قيمة Celsius وأضف 30. فـ 22°C × 2 + 30 = 74°F (الفعلي 71.6°F). دقّة في حدود 2°F تقريباً لنطاق 0–30°C، وهو يغطّي تقريباً كل درجات الطقس والداخل. وللعكس، اطرح 30 من Fahrenheit وانصِّف.

لماذا يُعيد محوّل درجة الحرارة لديّ القيمة 98.599999 عند تحويل 37°C؟

لأنّ 9/5 = 1.8 لا يمكن تمثيلها بدقّة في الفاصلة العائمة الثنائيّة، فتخرج 37 × 9 / 5 + 32 بقيمة 98.60000000000001 بدل 98.6. هذا سلوك IEEE 754، لا خلل. استعمل toFixed(2) للعرض، أو انتقل إلى مكتبة عشريّة إن كانت دقّة الأرقام المتأخّرة تهمّ في مجالك.

هل يمكنني تخزين درجات الحرارة كأعداد صحيحة لتجنّب مشاكل الفاصلة العائمة؟

نعم: خزِّنها بعُشر-السيلزيوس (درجة الحرارة مضروبةً في 10). فـ 37.0°C تصير 370، و22.5°C تصير 225. الحساب الصحيح دقيق، وتقسم على 10 عند حدّ العرض فقط. هذا نمط شائع في الأنظمة المدمجة وقواعد بيانات السلاسل الزمنيّة عالية الحجم التي يهمّ فيها القرص والمعالج.

كيف أتعامل مع أرقام بلا وحدات في استجابة API؟

لا تفعل. كل حقل درجة حرارة يجب أن يحمل وحدة صريحة، إمّا في اسم الحقل (temp_celsius، temp_k) أو في حقل شقيق unit. وإن كنتَ المستهلِك ولم تُوفّر API ذلك، وثِّق الافتراض صراحةً في الكود، واكتب اختبار عقد ينكسر إن تغيّرت القيمة الافتراضيّة للـAPI.

ما نقطة غليان الماء في المقاييس الأربعة كلّها؟

100°C = 212°F = 373.15 K = 671.67°R، عند الضغط الجوّيّ القياسيّ (جوّ واحد، 101.325 kPa). ويهمّ الضغط: عند ارتفاع دنفر، يغلي الماء نحو 95°C، وعلى قمّة إفرست أقرب إلى 71°C. نقطة الغليان كمّيّة تعتمد على الضغط، لا ثابت كونيّ.

هل تؤثّر درجة الحرارة في حسابات الفاصلة العائمة بشكل مختلف عن الأرقام الأخرى؟

لا، فقيم درجة الحرارة تتصرّف كأيّ رقم فاصلة عائمة. المطبّ العمليّ أنّ معاملَي 5/9 و9/5 في صيغ التحويل يُدخلان خطأ تقريب في كل خطوة تحويل. فلقيم Kelvin في نطاق 200–400، الدقّة وافرة. ولقيم Celsius الأقلّ من الصفر قرب حافّة الثنائيّات القابلة للتمثيل، تبقى الدقّة جيّدة أيضاً. المطبّ الحقيقيّ هو التحويلات المتسلسلة التي تُراكم أخطاء صغيرة. حوِّل مرّة واحدة، وخزِّن الشكل القانونيّ.

مقالات ذات صلة

عرض جميع المقالات